VOGONS

Common searches


Reply 20 of 32, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie
noshutdown wrote:

and i wanna know how mem.exe and chkdsk.exe reports free conventional ram?

well this is just realmode memory. Calculating that is easy.

you can

1 - walk, the MCB chain, remove your current app and count up all free memory. east to do!
2 - do a alloc all in dos which will return largest free memory block. keep allocating blocks until you run out, add them all up.

then test for ems, if present, get the count of free pages, multiply by 16kb since a page is 16kb.
then test for xms, if present, get how much is free.

I wrote a utility to walk the MCB and manipulate memory on my tandy 1000 sx to add blocks in umb to the chain (in dos3.3 there is no umb).

This is part of it I cut down for you as an example, builds with watcom as real mode exe

Filename
MCBLIST.ZIP
File size
13.87 KiB
Downloads
55 downloads
File comment
MCB list example in Watcom C
File license
Fair use/fair dealing exception

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 21 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie
BloodyCactus wrote:
well this is just realmode memory. Calculating that is easy. you can […]
Show full quote

well this is just realmode memory. Calculating that is easy.
you can

1 - walk, the MCB chain, remove your current app and count up all free memory. east to do!

I wrote a utility to walk the MCB and manipulate memory on my tandy 1000 sx to add blocks in umb to the chain (in dos3.3 there is no umb).

This is part of it I cut down for you as an example, builds with watcom as real mode exe

MCBLIST.ZIP

thanks a lot for the info. unfortunately i am not very experienced in programming so i can barely understand how it works, and there are some features in the code that i don't need, so i wonder if i got it right:
1.define a struct of MCB, and a pointer of it.
2.use int21h-52h to get the address of first MCB, and set the pointer to it.
3.sum up its size if its owner is 0.
4.move the pointer onto the next MCB(i havn't figured out how to yet) and repeat until its Signature is 'Z'.

Reply 22 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie

i wrote a little quick and dirty program(with borland c) to see if i got it right, but it only displayed 5 blocks and ended with a block type 0. can you tell me where i have done wrong?

#include <dos.h>
#include <iostream.h>

long freeram(int mode)
{
if ((mode<1)||(mode>2))
return -1;
struct mcb
{
unsigned char type;
unsigned short owner;
unsigned short size;
unsigned char unused[3];
unsigned char name[8];
};
mcb far *mcbpointer;
unsigned short far *temp1;
long freeram=0, maxfreeblock=0;
_AX=0x5200;
geninterrupt(0x21);
temp1=(unsigned short far*)MK_FP(_ES,_BX-2);
mcbpointer=(mcb far*)MK_FP(*temp1,0);
unsigned int blockcounter=0;
do
{
cout<<"block "<<(++blockcounter)<<" is "<<(mcbpointer->size)<<"*16 bytes, block type is "<<(int)(mcbpointer->type)<<".\n";
if (!(mcbpointer->owner))
{
cout<<"this block is free.\n";
freeram+=(mcbpointer->size);
if (maxfreeblock<(mcbpointer->size))
maxfreeblock=(mcbpointer->size);
}
mcbpointer+=((mcbpointer->size)+1);
}
while ((mcbpointer->type)=='M');
cout<<"last block type is "<<(int)(mcbpointer->type)<<endl;
if (mode==1)
return (freeram<<4);
else
return (maxfreeblock<<4);
}

int main(int argc, char **argv)
{
cout<<freeram(1)<<" bytes conventional ram free.\n";
cout<<"largest free block is "<<freeram(2)<<" bytes.\n";
return 0;
}

and the result is:
block 1 is 1*16 bytes, block type is 77.
block 2 is 4*16 bytes, block type is 77.
this block is free.
block 3 is 16*16 bytes, block type is 77.
block 4 is 9*16 bytes, block type is 77.
block 5 is 5236*16 bytes, block type is 77.
last block type is 0
64 bytes conventional ram free.

Reply 23 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie

i found it! its that far mcbpointer that overflowed, so i changed the way of moving onto the next block and its working now.

block 1 is 1*16 bytes long, block type is 77.
block 2 is 4*16 bytes long, block type is 77.
this block is free.
block 3 is 16*16 bytes long, block type is 77.
block 4 is 9*16 bytes long, block type is 77.
block 5 is 4112*16 bytes long, block type is 77.
block 6 is 36444*16 bytes long, block type is 90.
this block is free.
583168 bytes conventional ram free.
largest free block is 583104 bytes.

this is still quite surprising because dosbox start out at 632kb free, so the program itself took 62.5kb even though i compiled in tiny mode and only a few variables were defined.
i also want to know if these keywords work with other dos compilers?

Reply 24 of 32, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

you must pack your structures.

also last block is 'Z' and still valid, your skipping the last block.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 25 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie
BloodyCactus wrote:

also last block is 'Z' and still valid, your skipping the last block.

true but i have already observed and fixed that. as you can see from my last reply, the last block type reported is 90.
what shall i do to "pack my structures"?

i also noticed that the program reports ~570kb free when compiled in tiny mode, ~550kb in small mode, and ~600kb in large mode. in all modes the reported amount is close to farcoreleft(), so i wonder if its because large mode has no near heap, which is not reflected in the mcb chain? how do i add up the unused amount in near heap in tiby/small/medium mode?

Reply 26 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie
Scali wrote:
There are basically 3 kinds of pointers in 16-bit segmented mode. As you probably know, a pointer is a combination of two 16-bit […]
Show full quote

There are basically 3 kinds of pointers in 16-bit segmented mode.
As you probably know, a pointer is a combination of two 16-bit integers, segment and offset.
The linear address is formed by (segment*16)+offset.

A near pointer stores only the offset, the segment is the 'default' segment for data or code. The advantage is that pointers are smaller, and pointer arithmetic is faster, because the segment is fixed.
A far pointer stores offset and segment, but the segment is 'static'. That is, pointer arithmetic only updates the offset part. This is still relatively fast, but obviously limits you to a 64k block of data starting at the given segment.
A huge pointer updates both segment and offset, which allows you to address all memory as if it is linear. So you can use it for arrays of more than 64k, but it is also the slowest.

In a huge model, all pointers are huge by default.

thanks for the explaination, but do they still make much speed difference when running on 386 or newer cpus?

Reply 27 of 32, by Scali

User metadata
Rank l33t
Rank
l33t
noshutdown wrote:

thanks for the explaination, but do they still make much speed difference when running on 386 or newer cpus?

Yup. In 16-bit mode, you only have instructions and address modes to handle offsets, so only 'near' addresses.
Any far/huge pointer handling requires changing the segment, which just takes several instructions.

That's why 32-bit mode quickly became mainstream for games and other performance-critical software, once the 386sx and better CPUs were commonplace.
In 32-bit mode, your offsets are now 32-bit, and you can address 4 GB at a time, so you never need to deal with segments anymore. All address modes and special instructions such as lods, stos, movs will now update 32-bit offsets, which effectively give you a flat addressing model.
It makes handling datasets of more than 64k a lot faster and easier.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 28 of 32, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie
noshutdown wrote:

i also noticed that the program reports ~570kb free when compiled in tiny mode, ~550kb in small mode, and ~600kb in large mode. in all modes the reported amount is close to farcoreleft(), so i wonder if its because large mode has no near heap, which is not reflected in the mcb chain? how do i add up the unused amount in near heap in tiby/small/medium mode?

odd. mine does not change results based on changing small/large/huge/compact.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 29 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie
BloodyCactus wrote:

odd. mine does not change results based on changing small/large/huge/compact.

i read your program over and noticed that after you make a copy of the mcb chain, you treat the memory used by your own program as free, and merge it into the previous or next block if either is free. did i get it right?
this does correspond to the available ram of dos, but what i really want is "how much ram can i still abuse without getting into trouble" during my program. yes there is a lot to be concerned like the difference between near heap and far heap, and i have yet to find out how to new an object larger than 64kb rather than farmalloc...

Reply 30 of 32, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie

Under watcom, if you want to alloc the largest free block of ram in real mode,

#include <dos.h>
uint16_t segment;
uint16_t size_paras;
// ask for all, dos returns max size we can have
_dos_allocmem(0xFFFF, (unsigned short*)&size_paras);
// allocate max size then
_dos_allocmem(size_paras, (unsigned short*)&segment);

thats off top of my head, but should work.

in protected mode that wont work tho.

I'm still not clear what your real goal is.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--

Reply 31 of 32, by noshutdown

User metadata
Rank Oldbie
Rank
Oldbie
BloodyCactus wrote:

thats off top of my head, but should work.

in protected mode that wont work tho.

I'm still not clear what your real goal is.

what i want is:

#in real mode
cout<<"total unused ram in far heap.";
cout<<"largest free block in far heap.";
switch (memorymode)
{
case tiny:
case small:
case medium:
cout<<"total unused ram in near heap.";
cout<<"largest free block in near heap.";
}

i also found that counting the mcb chain doesn't reflect freed blocks, thats the same issue as coreleft() and farcoreleft(). heres some results:

initial status:
coreleft() reports 635088 bytes free, farcoreleft() reports 635088 bytes free.
block 5 is 896*16 bytes long, block type is 77, owner is 402.
block 6 is 39660*16 bytes long, block type is 90, owner is free.
634624 bytes free, largest free block is 634560 bytes long.

after mallocing 8*32kb blocks in far heap:
coreleft() reports 372816 bytes free, farcoreleft() reports 372816 bytes free.
block 5 is 17280*16 bytes long, block type is 77, owner is 402.
block 6 is 23276*16 bytes long, block type is 90, owner is free.
372480 bytes free, largest free block is 372416 bytes long.

freeing block 0.
freeing block 1.
freeing block 2.
freeing block 3.
freeing block 4.
freeing block 5.
freeing block 6.
//block 7 is not freed.
after freeing block 0~6:
coreleft() reports 372816 bytes free, farcoreleft() reports 372816 bytes free.
block 5 is 17280*16 bytes long, block type is 77, owner is 402.
block 6 is 23276*16 bytes long, block type is 90, owner is free.
372480 bytes free, largest free block is 372416 bytes long.

Reply 32 of 32, by BloodyCactus

User metadata
Rank Oldbie
Rank
Oldbie
noshutdown wrote:

i also found that counting the mcb chain doesn't reflect freed blocks, thats the same issue as coreleft() and farcoreleft(). heres some results:

you have a fundamental misunderstanding how dos memory and compilers work. Pretty much any dos compiler manages memory itself, not via dos (func 48/49/4A) with the MCB. Compilers will often allocate large blocks and internally manage them through its internal heap mechanism and using sbrk. malloc + free are not dosfunc 0x48 + 0x49.

--/\-[ Stu : Bloody Cactus :: [ https://bloodycactus.com :: http://kråketær.com ]-/\--