Common Heap foibles

Anything QL Software or Programming Related.
Post Reply
User avatar
NormanDunbar
Forum Moderator
Posts: 2470
Joined: Tue Dec 14, 2010 9:04 am
Location: Buckie, Scotland
Contact:

Common Heap foibles

Post by NormanDunbar »

As part of an article for the next eMagazine, I'm discussing the use of heaps in SMSQ/E. Specifically the common heap - which is where I'm seeing some things I don't yet understand and which don't appear to match up to the docs (QDOS/SMS Reference Manual, 4.5, and Pennel QDOS Companion)

Summary
  • The rounding doesn't appear correct; It's not always to the next multiple of 8;
  • None of the docs mention that the block header is included in the space allocated?
  • Is the block header pointer to next free space relative?
  • The block header doesn't appear correct either;
  • Owning job Id seems always to be zero.
  • Request 1 byte, gets 32 bytes returned in D1, expected 24.
  • Request 10 bytes, also gets 32 bytes returned in D1, expected 32.
  • Request $3f2 bytes, gets $410 bytes returned in D1, expected $408.
  • Request $400 bytes, also gets $410 bytes returned in D1, expected $410.

Detail

I know that there's a 16 byte overhead included before the start of the common heap space allocated, detailing:
  • Size of the block;
  • (Relative?) pointer to the next free space in the common heap (or the address of the device driver code to free this block);
  • Owning Job Id;
  • Address of a byte to be set when this block is freed.
If I ask for 1 byte of common heap, I expect to get 8, plus an overhead of 16 giving a grand total of 24 bytes, but $20 (32) is returned in D1 as the size of the block allocated. Is there a miniumum allocation size for a block? Or is rounding to a multiple of 16 and not 8?

None of the docs I've seen specifically mention that the overhead is included in the value returned in D1 from SMS.ACHP/MT_ALLOC. Is this definitely the case? It appears to be as requesting 10 bytes also gives me $20 according to D1. (10 rounded to 16 plus 16.)

On top of the weird rounding up, the 4 long words ahead of the base of the area allocated are looking strange. I get:

-$10 Size of block = $20
-$0C Pointer to next free/dealloc code = $00
-$08 Owner job ID = $00
-$04 Address to set when block freed = $00

EDIT: Of course S*BASIC owns it, you CALLed the code, it's not in a job! Duh!

I can understand the address to set being zero, but there doesn't seem to be a (relative?) pointer to the next free block. Unless the pointer is from the end of the allocated block? (Which I doubt!)

What am I not understanding?

QPC on Linux Mint 20.3 Under wine. 64 bits.


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: Common Heap foibles

Post by mk79 »

The rounding doesn't appear correct; It's not always to the next multiple of 8;
mem_alhp has an allocation unit of 8 bytes, common heap allocations 16 bytes. If that would leave a 16 byte gap it can also be 32. In any case this is a implementation detail not to be relied upon.
None of the docs mention that the block header is included in the space allocated?
That is a bit weird, yes. But personally I've never checked the value, either you got the memory you wanted or you didn*t.
Is the block header pointer to next free space relative?
Yes.
I can understand the address to set being zero, but there doesn't seem to be a (relative?) pointer to the next free block. Unless the pointer is from the end of the allocated block? (Which I doubt!)
The free block pointer is only valid on free blocks (to get to the next)! It's a linked list of free blocks so to say, with sys_chpf as an anchor.

Here's a little utility I wrote to debug heap and memory corruption problems, it dumps the current heap structure to a file.

Code: Select all

100 INPUT#0,'File> ';File$
110 OPEN_NEW#3,File$
120 PRINT#3,"Freemem :"; FREE_MEM/1024; "kb"
130 PRINT#3\\"Common heap"\
140 common -1
150 PRINT#3\\"TPA"\
160 TPA -1
170 CLOSE#3
990 :
1000 DEFine PROCedure common(jobID)
1010 adr = PEEK_L(HEX('28004'))
1020 chpfr = HEX('28004') + PEEK_L(HEX('28008'))
1030 endHeap = PEEK_L(HEX('2800C'))
1040 heap(jobID)
1050 END DEFine common
1060 :
1070 DEFine PROCedure TPA(jobID)
1080 adr = PEEK_L(HEX('28014'))
1090 chpfr = HEX('28014') + PEEK_L(HEX('28018'))
1100 endHeap = PEEK_L(HEX('28020'))
1110 heap(jobID)
1120 END DEFine TPA
1130 :
1140 DEFine PROCedure heap(jobID)
1150 :
1160 ch% = 3
1170 flag = 0
1180 PRINT#ch%,CHR$(10)&'address  '!'length'!'driver'!'ownr'!'rflag    '!'name'
1190 :
1200 REPeat heaploop
1210   IF adr >= endHeap: EXIT heaploop
1220   CHP_LEN = PEEK_L(adr)
1230   CHP_JOB = PEEK_W(adr + 10)
1240   IF jobID >= 0 AND jobID <> CHP_JOB: GO TO 1350
1250   CHP_DRIVR = PEEK_L(adr + 4)
1260   CHP_OWNER = PEEK_L(adr + 8)
1270   CHP_RFLAG = PEEK_L(adr + 12)
1280   PRINT#ch%,HEX$(adr,32)&' '!HEX$(CHP_LEN,24)!HEX$(CHP_DRIVR,24)!HEX$(CHP_JOB,16)!HEX$(CHP_RFLAG,32);
1290   IF chpfr = adr THEN
1300     PRINT#ch%,'  free': chpfr = chpfr + CHP_DRIVR
1310   ELSE
1320     PRINT#ch%,'  '&JOB$(CHP_OWNER)
1330   END IF
1340   flag = 1
1350   adr = adr + CHP_LEN
1360 END REPeat heaploop
1370 :
1380 IF NOT flag: PRINT#ch%,'Nothing found': ELSE PRINT#ch%,'Finished'
1390 END DEFine heap


User avatar
NormanDunbar
Forum Moderator
Posts: 2470
Joined: Tue Dec 14, 2010 9:04 am
Location: Buckie, Scotland
Contact:

Re: Common Heap foibles

Post by NormanDunbar »

Thanks Marcel, I'll hopefully get a better look at your reply when MrsD stops giving me stuff to do! :(

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
Post Reply