home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / programs / compress / packers / imploder4.0 / imploder / docs / techno < prev    next >
Text File  |  1995-02-27  |  17KB  |  355 lines

  1. This document deals with the inner workings. If you're a tech type, and are
  2. interested in somewhat deeper lying aspects relating to how the Imploder
  3. operates, chances are you'll find it here.
  4. Subjects covered are:
  5.  
  6. - Compression
  7. - Decompression
  8. - Reversibility
  9. - The Library
  10. - Overlayed Files
  11. - Merging
  12. - ARP
  13. - The Music
  14. - The Copperlist
  15. - 68040 Cache Coherency
  16.  
  17.  
  18. ** Compression **
  19.  
  20. The Imploder (we only recently learned :-) does LZ77 like compression with a
  21. per-mode static Huffman coding step on the various parts of the skip, offset
  22. and length tuples. Due to the efficient encoding, a tuple can require less
  23. than 12 bits, and thus strings of 2 bytes length are encodable with a decent
  24. gain (given small Huffman patterns corresponding to likely circumstances).
  25.  
  26. To speed up the string searching, the turbo mode causes the accessible strings
  27. to be indexed using a hashing table. However, the fact that strings with a
  28. minimum size of two bytes are still potential candidates for compression,
  29. requires the hashing function to necessarily be rather simplistic. When the
  30. implosion algorithm processes highly redundant data, entries in the hashing
  31. table tends to get very imbalanced, causing a reduction in performance.
  32. For most types of data, notably executables, this isn't the case though.
  33.  
  34.  
  35. ** Decompression **
  36.  
  37. The goal of decompression is to reproduce the segment list of the
  38. original program. This is a linked list of data/code/bss hunks, some
  39. of which require being positioned in chip memory.
  40.  
  41. The decompression code will have to fill the data and code hunks with
  42. the decompressed data, and, if required, perform relocation of absolute
  43. references.
  44.  
  45. The Imploder lets LoadSeg allocate all target hunks (as BSS). These
  46. are at the start of the hunk list. This is followed by a hunk with
  47. the decompression code (only for non-library imploded programs),
  48. a compressed data hunk (normally about 50% of the static data size,
  49. depending on compression gain ofcourse), and a decompression buffer
  50. (only upto 17K in size).
  51. As you can see, no allocations need to be done, so the exploding
  52. process will never fail.
  53.  
  54. During decompression time, data is decompressed from the compressed data
  55. buffer into the decompression buffer until it has filled. It then empties
  56. this buffer by filling hunks and processing reloc tables.
  57. When the buffer has been emptied, the process repeats until all data has
  58. been scatter-decompressed across the target hunks.
  59.  
  60. Now you might ask, why not directly decompress to the target hunks
  61. instead of using a decompression buffer?
  62. This is because the the Imploder uses the decompressed data to
  63. decompress, and needs to be able to easily access it (for speed).
  64. Referencing data distributed across several hunks is much more
  65. cumbersome.
  66.  
  67. An added bonus of having separate source and target memory regions is that
  68. a notation can be used that doesn't gain under rare circumstances, but on
  69. average yields better results (No chance of source/target pointer
  70. collision).
  71.  
  72. When explosion has finished, the decompression buffer, code and data
  73. hunks are freed, and memory usage reduced to what it would have been
  74. for a non-imploded version of the program.
  75.  
  76. People often compare the Imploder to the Power Packer. The Imploder
  77. decompresses faster and looks cooler [:-)], but the most interesting
  78. differences lie in the implementation of the various steps of the
  79. decompression proccess. So let's contrast the advantages of the
  80. Imploder's approach with the Power-Packer's implementation.
  81.  
  82. - By having LoadSeg allocate all memory as BBS hunks, explosion will
  83.   never fail.
  84.   The Power-Packer on the other hand allocates hunks. If it fails it
  85.   will simply exit. Power Packed programs launched from the WorkBench
  86.   thus won't reply the startup message, which will be left dangling in
  87.   memory forever.
  88.  
  89. - Memory doesn't get fragmented. The explosion related hunks are at
  90.   the end of the seglist and thus were allocated (by LoadSeg) AFTER
  91.   the target hunks.
  92.   This isn't true for the Power-Packer. It does leave a hole in your
  93.   free memory list when it frees its decompression stuff.
  94.  
  95. - Additional memory usage is only about 50% of the static data size +
  96.   the size of the decompression buffer, which is always small relative
  97.   to large programs (maximum 17k).
  98.   So a 30K program might require 62K to decompress (30+15+17), a 300K
  99.   program will require 467K (300+150+17), assuming a 50% compression
  100.   reduction.
  101.   The memory usage report generated after a program has been imploded
  102.   includes BSS hunks. I've discussed only static data here. BSS hunks
  103.   don't require any extra memory usage of course.
  104.   Power-Packed files require a buffer as large as the original program
  105.   for both compressed data storage and decompression. Memory usage is
  106.   therefore always about twice the static data size (again ignoring BSS)
  107.   while for the Imploder it drops to 1.5 for executables large enough to
  108.   matter memory wise.
  109.  
  110. (In this comparison I'm talking about executables as produced
  111.  by Power-Packer version 3.0b.)
  112.  
  113. Non-library imploded programs have a small first hunk that calls the
  114. decompression code hunk at the end, and frees these last three hunks. 
  115. For library imploded programs this freeing occurs in the library, so no
  116. preceding hunk is needed.
  117.  
  118.  
  119. ** Reversibility **
  120.  
  121. Before compression the Imploder preprocesses executables. It kicks out all
  122. the redundant stuff by merging subreloc tables referring to the same hunk,
  123. sorting relocs (improves compression), removing debug symbols etc. etc.
  124. This is what all those info blurbs in the text window are about.
  125.  
  126. So the deploded executable isn't guaranteed to be byte by byte identical
  127. as far as loadfile control codes are concerned.
  128.  
  129. What is guaranteed is that the memory images created when the original,
  130. imploded and deploded program versions are loaded are identical.
  131.  
  132. So the deplosion process isn't 100% reversible. Normally this is no
  133. problem. The reason for uncrunching is mostly wanting to recompress
  134. an executable using a different compression mode, or having a quick
  135. peek at the code e.g. when applying a patch with something like
  136. NewZap.
  137. If however you expect to need the debug symbols, or (important)
  138. require the executable to be in the _exact_ original format in order
  139. to have things like lpatch updates to applied, you're out of luck
  140. if you've only got the compressed executable. So always keep the
  141. original archives/disks!
  142.  
  143. This is yet another argument for retaining the original archives.
  144. The Imploder is an online space creator not a distribution
  145. archiver (See the "Philosophy" text).
  146.  
  147.  
  148. ** The Library **
  149.  
  150. The library code has been unrolled a bit, and optimized here and there
  151. in order to achieve optimal performance. This makes it faster than the
  152. normal explosion algorithm.
  153.  
  154. If you library implode a program there is NO way in which the program,
  155. after explosion, will be able to notice. If you make sure the library
  156. is resident, this is also true for any executable file loaded for any
  157. purpose by any program.
  158.  
  159. For normal etc. imploded programs the startup/cleanup hunk mentioned
  160. at the end of the "decompression" section might be detected if a program
  161. goes through contortions involving finding the segment list via murky
  162. DOS structures instead of simply doing PC relative hunk start referencing
  163. which also works from the WorkBench.
  164. I haven't encountered any programs that do this. Still this is yet another
  165. reason to use the library; there is not even the slightest chance of it
  166. being incompatible with an executable.
  167.  
  168. Note that the Loadseg vector is patched in an "intelligent" manner; it
  169. will install fine for pre 2.0 kickstarts (braindead jumptable format)
  170. as well as in BCPL free systems (2.0+)
  171.  
  172. Under pre 2.0, when a library imploded file is run from the WorkBench, and
  173. the explode.library isn't resident yet, Exec will try to load the library
  174. from disk. The process's message port however is in use by the WorkBench
  175. reply message, and until it has been replied, it cannot be used by the
  176. DOS in order to send packets. Thus the DOS gurus.
  177.  
  178. Also, BCPL code doesn't jump through the the library vector. The only
  179. structural problem with this are handlers. These are loaded by the DOS,
  180. and the DOS is BCPL code, again ONLY under < 2.0. Under 2.0 the library
  181. works just like intended when it was first conceived. Transparently that
  182. is.
  183.  
  184.  
  185. ** Overlayed Files **
  186.  
  187. The Imploder compresses the load part of an overlayed file as if it were a
  188. normal executable file. Subsequently, the overlay table and the overlayed
  189. program section are appended.
  190. It then tries to adapt the overlay table. Because different types of
  191. overlay supervisors are in use, the format of the overlay table isn't
  192. known to the Imploder. The only assumption made is that the overlay table
  193. contains seek-offset longwords, at longword aligned locations, that point
  194. into the file to the hunk_header ($3F3) identifiers of the overlayed
  195. program sections.
  196. This is how the standard overlay manager operates, but nothing prevents
  197. a programmer with sufficient technical knowledge to create a novel overlay
  198. format (e.g. selfextracting DImp files).
  199.  
  200. If the Imploder finds one of these offsets, it is adjusted by the amount
  201. the initial load part of the executable file has compressed.
  202. The deplosion algorithm also tries to find these offsets when restoring the
  203. overlay table. Thus there is always a very small chance that the imploder
  204. will adapt a longword that was never meant to be an offset.
  205.  
  206. An overlayed file gets its information from the loader in four longwords,
  207. at the start of the first hunk. In an imploded overlayed file, this hunk is
  208. the root hunk, and after decrunching these longwords are adjusted and moved
  209. into the first hunk of the actual program (the second hunk of the seglist).
  210.  
  211. Evidently this process can never be 100% deterministic, so take heed and
  212. test any overlayed programs you've Imploded. Or don't use overlay implosion
  213. at all if you can spare the bits.
  214.  
  215.  
  216. ** Merging **
  217.  
  218. Though modern linkers/compilers typically produce executables with one code
  219. hunk and one data hunk, there are still some old executables and less evolved
  220. linkers around. The merging option was implemented when executables with
  221. sufficient hunks to cause a lot of redundancy were still commonplace.
  222.  
  223. Every hunk requires a longword in the allocation header, plus a hunk ID,
  224. load size, and hunk end ID. That's 16 bytes per hunk, and thus saved for
  225. every merge action. Doesn't sound like much, but generally hunks also
  226. have reloc tables. These waste a lot more space, especially with references
  227. to a lot of different hunks, though there's no easy equation.
  228.  
  229. The merging step merges matching hunks (data-data, chipdata-chipdata,
  230. code-code) into hunks of upto the merge threshold in size. The actual
  231. size is of course determined by the sum of the sizes of the composite hunks,
  232. and may very well be a bit less than the specified threshold.
  233.  
  234. Obviously this process discards redundant data in an irreversible fashion,
  235. so deploding the executable won't reverse it.
  236.  
  237. Lots of tiny hunks cause memory fragmentation, but increase the chance of
  238. the program being able to load when the system is fragmented, and low on
  239. memory. Thus there is a kind of optimal balance that varies from system
  240. to system. In general it can be said that hunks less than 10K or more than
  241. 100K are "bad".
  242.  
  243. Another factor is that loading a program with many tiny hunks causes the
  244. LoadSeg function to issue double as many tiny read commands, thus bogging
  245. down the speed with which an executable can be loaded into memory.
  246.  
  247. For simplicity's sake, I've chosen for the Imploder to process executables
  248. within a single buffer, without the need for additional backup buffers.
  249. Thus, removing redundant information, and copying hunk data during the
  250. merging and reloc cleanup process involves moving or mirroring large parts
  251. of the buffer. This is why merging can take a while when processing a large
  252. executable with a hundred or so hunks.
  253.  
  254.  
  255. ** ARP **
  256.  
  257. Programs written for use with the ARP shell are able to specify the
  258. stacksize they require inside the first hunk of their executable. If
  259. such a program is normal or pure imploded, the segment list won't become
  260. visible until the program is run. Thus ARP has no way of finding out what
  261. the proper stacksize should be.
  262. Library imploded programs have no trouble with this because they are
  263. already decrunched after they are loaded into memory with LoadSeg.
  264. (Provided the library has already been made resident.)
  265.  
  266. The Imploder will recognize these files and report on them. If the
  267. requested stack-size is larger than the usual minimum (4000 bytes)
  268. a warning will be printed, and you'll be urged to use only library
  269. implosion.
  270.  
  271. The chance of a programmer relying on a soon to be obsolete shell for
  272. setting a stack LARGER than the usual default is rather slim though.
  273. It would have been very nice if 2.0 had sported such a stack setting
  274. feature, and indeed it had been planned, but was never implemented due
  275. to lack of time on the part of the Commodore programmers.
  276.  
  277. We'll be on the lookout for any future changes to the executable file
  278. format in order to fix any potential incompatibilities before they'll
  279. cause problems.
  280.  
  281.  
  282. ** The Music **
  283.  
  284. When we got word the CIA-A timer was used by the OS under 2.0, we switched to
  285. trying to allocate first CIA-A and if not available CIA-B to drive the music.
  286. However the CIA-B interrupt priority is too high and can interfere with things
  287. like serial transfer. So Paul got this great idea to keep on using a CIA for
  288. precision timing purposes, but drop down to a SoftInt for doing the actual
  289. work, modulations, etc. This works great, the amount of code executed under
  290. CIA priority is now negligible.
  291. Recently, the CATS started feeling guilty about hijacking the CIA-A timer and
  292. thus created "Jumpy the magic timer device". If I understood things correctly
  293. the latest 2.0 timer device moves out of the way and starts using a less
  294. accurate timing source whenever an application tries to allocate the CIA-A.
  295. Pauls music driver can run of both CIA-A and CIA-B, and it would be a pity
  296. to make Jumpy jump without good reason, so he changed the alloction sequence
  297. from A-B to B-A.
  298.  
  299.  
  300. ** The Copperlist **
  301.  
  302. There are a couple of unavoidable quirks when one uses copperlists on Intuition
  303. screens. On certain machines, probably PAL, under certain circumstances, dragging
  304. a dense copperlist past scanline 256 or so will cause some video crud to appear
  305. at the top of the display. This can't hurt, but it sure does look ugly. I suspect
  306. this is a hardware misfeature because it ain't fixed yet under 2.0
  307. This was the reason why the screen of older Imploder versions wasn't draggable;
  308. you might just think this muck was our doing.
  309.  
  310. Second problem is that copperlists "shine through" onto other screens in front.
  311. For this reason we've choosen a colour > 4 for the level bars, so this is never
  312. observable with screens less than 3 bitplanes deep.
  313. The 2.0 OS support proper copperlist clipping, but it has been disabled by
  314. default for compatibility reasons (yeach). Supposedly there is a bit somewhere
  315. in the graphics base to turn this back on, so I'm sure, in due time, there will
  316. be some preference editor to re-enable this.
  317.  
  318.  
  319. ** 68040 Cache Coherency **
  320.  
  321. With the advent of the 68040 processor, programs that diddle with code which is
  322. subsequently executed will be prone to some problems. I don't mean the usual
  323. self-modifying code causing the code cached in the data cache to no longer
  324. be as the algorithm expects. This is something the Imploder never had a
  325. problem with, indeed the Imploder has always worked fine with anything
  326. upto and including an 68030.
  327.  
  328. The reason the 68040 is different is that it has a "copyback" mode. In this
  329. mode (which WILL be used by people because it increases speed dramatically)
  330. writes get cached and aren't guaranteed to be written out to main memory
  331. immediately. Thus 4 subsequent byte writes will require only one longword
  332. main memory write access. Now you might have heard that the 68040 does
  333. bus-snooping. The odd thing is that it doesn't snoop the internal cache
  334. buses!
  335.  
  336. Thus if you stuff some code into memory and try to execute it, chances are
  337. some of it will still be in the data cache. The code cache won't know about
  338. this and won't be notified when it caches from main memory those locations
  339. which do not yet contain code still to be written out from the data caches.
  340. This problem is amplified by the absolutely huge size of the caches.
  341.  
  342. So programs that move code, like the explosion algorithms, need to do a
  343. cache flush after being done. As of version 4.0, the appended decompression
  344. algorithms as well as the explode.library flush the cache, but only onder OS
  345. 2.0. The reason for this is that only OS 2.0 has calls for cache-flushing.
  346.  
  347. This is yet another reason not to distribute imploded programs; they might
  348. just cross the path of a proud '40 owner still running under 1.3.
  349.  
  350. It will be interesting to see how many other applications will run into
  351. trouble once the '40 comes into common use among Amiga owners. The problem
  352. explained above is something that could not have been easily anticipated
  353. by developers. It is known that the startup code shipped with certain
  354. compilers does copy bits of code, so it might very well be a large problem.
  355.