Improving Queue Code

Started by
12 comments, last by Ravyne 16 years, 2 months ago
Its gotten late, so I'll have to reply with a more in-depth answer tomorrow, I may actually PM you, due to my concern for polluting the applicant pool.

However, one quick note I'll make is that I read the question specification differently than you. I read the question specification as indicating that you had *exactly* 2048 bytes in which to store *everything* -- book-keeping included. Perhaps you assumed otherwise, perhaps you were told otherwise, but this makes your implementation very different than mine.

Your implementation uses 384 extra bytes to keep the books. In contrast, mine uses only 256 bytes for book-keeping, and its embedded within the 2048 byte data area. On the other hand, it could be me that was mistaken, and perhaps how I read the specification was not in line with what they intended [grin]

throw table_exception("(? ???)? ? ???");

Advertisement
Quote:Original post by ravyne2001
Its gotten late, so I'll have to reply with a more in-depth answer tomorrow, I may actually PM you, due to my concern for polluting the applicant pool.

However, one quick note I'll make is that I read the question specification differently than you. I read the question specification as indicating that you had *exactly* 2048 bytes in which to store *everything* -- book-keeping included. Perhaps you assumed otherwise, perhaps you were told otherwise, but this makes your implementation very different than mine.

Your implementation uses 384 extra bytes to keep the books. In contrast, mine uses only 256 bytes for book-keeping, and its embedded within the 2048 byte data area. On the other hand, it could be me that was mistaken, and perhaps how I read the specification was not in line with what they intended [grin]

Hmm, They told me that - " The maximum size allowed for storage of the queued data is MAX_DATA_SIZE."

w.r.t the extra bytes, thats kinda flexible depending on what constants you define. I think I can get it down to ~240 (don't remember the exact number) but it affects the performance too so I kinda chose a sweet spot.



--------------------------------------"Those alien bastards are gonna pay for ruining my ride !"
Here's a few things I spotted. Nothing really major though.

The MEM_USED calculation is a little optimistic - unless you actually bit pack the arrays manually it'll use more memory than that. I'd go with sizeof(Data) + sizeof(Chunks) + sizeof(Queues).

For size optimization your CHUNKS structure is somewhat inefficient - it's a bitfield with a total of 9 bits used. Most compilers would expand that to at least 16 bits, and maybe 32. If it's 32 then that array is 1024 bytes.

The simplest improvement is to just double the chunk size so you only need 8 bits per chunk, and half the number of chunks. You can then use an array of unsigned chars which gives a total of 128 bytes.

Big optimization: To save on the big loop searching for an unused chunk what I'd have done is created one extra hidden queue at the start which contains all free chunks. You then simply move chunks on and off the front of the free queue to allocate and deallocate chunks. You could even drop the free chunk bit if you did that, and therefore leave the chunk size at 8. That saves more memory than the extra QUEUE structure takes.

Minor optimization: As a QueueHandle is unsigned testing it for >=0 is completely pointless - unsigned values are never negative! Of course most compilers will optimize the pointless test away so it's a minor issue.

There's also quite a few 'magic' constants used in the code, which all seem to be written in hex. I'd probably have used decimal for most of them, and maybe defined 'used' and 'unused' constants up front. That's just a style thing though.
So far, I'll agree with the sentiments that have been stated already. In particular, the use of a free-list is the most important win since it eliminates that nasty linear search and the need for an "is-active" marker. Technically, a stack makes a better free-list in theory due to cache-coherence, but since you've already got the Queues in place, they cost you nothing to implement.

Stylistically, there is a disturbing lack of helper functions -- granted, I don't see a ton of code duplication, but breaking out small bits of functionality into functions makes the code easier to read and understand, which is what you want when someone is analyzing your code and making a judgment about you. For the same reason, you should use better variable names in some instances -- i, j and k, for example, are generally only acceptable as loop indexers but you've used them to hold whether a given block is active and where the start and end blocks are in some instances. Similarly, many of the comments are redundant because they only state what is about to be done. This would have become more apparent had you made good use of helper functions. The same applies to your function heading comments -- they don't contain any more information than the function signature, so they are redundant. They add nothing to my understanding of the code. They should indicate the following: What the function does (you have this, essentially), how it goes about it (briefly), what the parameters are expected to contain, what the function returns, what assumptions are made, what restrictions are enforced, what errors are trapped, and what happens when a restriction fails to be met or an error occurs. These things add value to my understanding; just restating the function signature in prose does not.


Given your location, the likelihood of it being the same company is high, but the problem statement has changed significantly if so. I was never given a header, instead the interface was specified and the header was up to me to implement. Another important difference is that your specification uses QueueHandles, while the spec I worked from specified that Queues were given as pointers, which certainly influenced certain design decisions I made. Reading through it once again on their website, the problem statement I worked from clearly indicates that *all* storage other than local variables must come from the 2K data buffer:

Quote:Your code is not allowed to call malloc() or other heap management routines. Instead, all storage (other than local variables in your functions) must be within a provided array.


The specification I was given is still intact, as I remember it, on the company's website. So either they've changed the problem specification since then and not updated their jobs page, or it is indeed a different company.


Since we've worked from different specs, and the remainder of my optimizations and neat tricks are basically dependent on the interface I was given, I won't post any of it here since its not directly applicable. However, if you're really interested feel free to PM me and I'll supply an in-depth explanation of my approach and some excerpts of code.

throw table_exception("(? ???)? ? ???");

This topic is closed to new replies.

Advertisement