Mecacomco C (and C68, BTW) are full-blown C compilers compared to Digital C, which is Small C and has to live with its limitations. Both support the register storage class. As it stands, register is only a recommendation from the developer to the compiler that a variable is going to see heavy usage and it would make sense to put it in a register. In case the compiler runs out of unassigned registers, or sees, for example, that the variable's address is taken anywhere, it will simply ignore this recommendation (but might also put other variables into registers where you didn't explicitly say so).bwinkel67 wrote: So the source has local variables set up with the register directive (REG), which suggests that some of the older compilers can assign a register to a specific variable. I imagine that would speed things up. Unfortunately Digital C SE doesn't give that feature. I'm guessing Metacomco C does? That's got to be how it is still faster.
Dhrystone compiled on BBQL with Digital C SE
Re: Dhrystone compiled on BBQL with Digital C SE
ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
- XorA
- Site Admin
- Posts: 1382
- Joined: Thu Jun 02, 2011 11:31 am
- Location: Shotts, North Lanarkshire, Scotland, UK
Re: Dhrystone compiled on BBQL with Digital C SE
That is a bloomin odd choice for any C implementation on QL, as the natural size is 32bits or 8bjts depending how you look at the CPU.which is 16 bits on the QL
Graeme
Re: Dhrystone compiled on BBQL with Digital C SE
Digital C SE doesn't have a short specification, only int and long. With other compilers (I don't know the specifics ot Metacomco C or C68 but I'm going to guess they do) you have short, int, and long. In that case, on a 32 bit system int and long would be 32 bits and short would be 16 bits. On a 64 bit system, short would be 16 bits, int would be 32 bits, and long would be 64 bits. So in Digital C SE's instance, the 16 bits makes sense.XorA wrote:That is a bloomin odd choice for any C implementation on QL, as the natural size is 32bits or 8bjts depending how you look at the CPU.which is 16 bits on the QL
Graeme
Re: Dhrystone compiled on BBQL with Digital C SE
Yeah, that's what I'm running into with regard to speed in Digital C SE...not being able to specify a variable as a register, which is costing me speed. I'm trying to figure out ways around that since I can't explicitly specify register. I'm sure I'll find other creative ways to optimize...that's part of the fun challenge.tofro wrote:Mecacomco C (and C68, BTW) are full-blown C compilers compared to Digital C, which is Small C and has to live with its limitations. Both support the register storage class. As it stands, register is only a recommendation from the developer to the compiler that a variable is going to see heavy usage and it would make sense to put it in a register. In case the compiler runs out of unassigned registers, or sees, for example, that the variable's address is taken anywhere, it will simply ignore this recommendation (but might also put other variables into registers where you didn't explicitly say so).
Digital C SE is an augmented Small C. It adds its own implementation of floating point. I think it also added the long integer type, because when reading the manual it states that SE has introduced long. This leads me to believe the non-SE version didn't have long so it was likely the one more closely aligned with Small C.
Re: Dhrystone compiled on BBQL with Digital C SE
Here are some updated results on Dhrystone (includes both version 1.1 and 1.2 of Dhrystone):
I got these values on Q-Emulator running in real-time on my 68K classic Mac Emulator (Basilisk II). I don't usually use Q-Emulator so I don't have a licensed Windows version but the old 68K classic version (3.0.4) seems to be fully functional. I have to say, Q-Emulator gave me the same result (196 Dhrystones) that my QL gave me. I was going to re-run all these on the QL but my vDrive stopped functioning today so it's not as easy to get it transferred over.
Note that the C68 version runs 500,000 iterations so it takes close to half an hour to get a result.
So next is to see if I can improve on the Digital C SE version. I can't force variables to registers, but I can unfold loops, and force caching, to improve some things. Would like it to get at least as good as the Metacomco version.
The only other results I still need is GCC's cross-compiled version for the QL. I read somewhere that it is even faster than C68. Still, 282 Dhrystones is pretty impressive.
- Digital C SE with a few optimizations on v1.1: 164
- Metacomco C on v1.1 (Franz Krojer , 1988): 196
- C68 on v1.2 (Franz Krojer, 1994): 282
I got these values on Q-Emulator running in real-time on my 68K classic Mac Emulator (Basilisk II). I don't usually use Q-Emulator so I don't have a licensed Windows version but the old 68K classic version (3.0.4) seems to be fully functional. I have to say, Q-Emulator gave me the same result (196 Dhrystones) that my QL gave me. I was going to re-run all these on the QL but my vDrive stopped functioning today so it's not as easy to get it transferred over.
Note that the C68 version runs 500,000 iterations so it takes close to half an hour to get a result.
So next is to see if I can improve on the Digital C SE version. I can't force variables to registers, but I can unfold loops, and force caching, to improve some things. Would like it to get at least as good as the Metacomco version.
The only other results I still need is GCC's cross-compiled version for the QL. I read somewhere that it is even faster than C68. Still, 282 Dhrystones is pretty impressive.
Re: Dhrystone compiled on BBQL with Digital C SE
Ok, finally ran my Digital C SE version on my QL (read the "Serial connection between QL and PC" to see how I had to get the executable to my QL the old-school way. It actually ran faster at 176 Dhrystones. Weird because the Metacomco version ran at 196, same as on Q-emulator. The one small cavat, small dots are appearing in the middle of the screen, so I seem to be writing into screen memory somewhere which I'll have to debug. Q-emulator (and QLAY), both with 128K memory setting and running JSU ROM, didn't show that.
So with legitimate small optimizations, I get 176 Dhrystones to 196 Dhrystones. Still far off form the C68 version though
So with legitimate small optimizations, I get 176 Dhrystones to 196 Dhrystones. Still far off form the C68 version though
Re: Dhrystone compiled on BBQL with Digital C SE
Looking further at my Digital C SE implementation of Dhrystone, since it seems to be writing to screen memory when running on my actual BBQL (i.e. I get little dots in the middle of my screen), I went over the code to figure out why. So in both of Franz Krojer's implementations of Dhrystone, version 1.1 (compiled with Metacomco) and version 1.2 (compiled with C68), it has the following code snippet (I marked up the two lines of interest with /* <-- ??????? */):
Looking at this code, I was confused by the lines marked with /* <-- ??????? */ because in Proc3() you have a pointer to RecordPtr (i.e. RecordPtr*) and in Proc1() you are only sending a RecordPtr (i.e. the types misalign). That's critical because in Proc3() you then re-reference that pointer to set it -- but you never de-referenced it when calling the function, so it never gets updated in Proc1() and any subsequent code that uses that variable (it's tied to a global) may be looking at a NULL pointer, which could cause things to speed up a bit since you may now no longer follow a linked-list of record pointers (I need to figure out if that's the case).
Looking here at some original source with comments:
https://github.com/Keith-S-Thompson/dhr ... ces/dhry-c
It verifies my hunch as in Proc1() they add a de-reference operator to the Proc3() call:
That code changed it a bit to get rid of that ugly #define that, when expanded, causes a messy looking procedure call in the first code example, i.e.
...which is equivalent in C to:
...yes, not very pretty code.
Just curious if I'm mis-reading the QL Metacomco C and C68 code here? Anyone with a good C background that has used either of these QL C compilers have an idea if I'm right or wrong here?
Code: Select all
struct Record {
struct Record* PtrComp;
Enumeration Discr;
Enumeration EnumComp;
OneToFifty IntComp;
String30 StringComp;
};
typedef struct Record RecordType;
typedef RecordType* RecordPtr;
...
void Proc1(PtrParIn)
REG RecordPtr PtrParIn;
{
#define NextRecord (*(PtrParIn->PtrComp))
structassign(NextRecord, *PtrGlb);
PtrParIn->IntComp = 5;
NextRecord.IntComp = PtrParIn->IntComp;
NextRecord.PtrComp = PtrParIn->PtrComp;
Proc3(NextRecord.PtrComp); /* <-- ??????? */
if (NextRecord.Discr == Ident1) {
NextRecord.IntComp = 6;
Proc6(PtrParIn->EnumComp, &NextRecord.EnumComp);
NextRecord.PtrComp = PtrGlb->PtrComp;
Proc7(NextRecord.IntComp, 10, &NextRecord.IntComp);
} else
structassign(*PtrParIn, NextRecord);
#undef NextRecord
}
...
void Proc3(PtrParOut)
RecordPtr* PtrParOut; /* <- this is equivalent to having 2 asterisks, i.e.: struct Record** PtrParOut; */
{
if (PtrGlb != NULL)
*PtrParOut = PtrGlb->PtrComp; /* <-- ??????? */
else
IntGlob = 100;
Proc7(10, IntGlob, &PtrGlb->IntComp);
}
Looking here at some original source with comments:
https://github.com/Keith-S-Thompson/dhr ... ces/dhry-c
It verifies my hunch as in Proc1() they add a de-reference operator to the Proc3() call:
Code: Select all
Proc_1 (Ptr_Val_Par)
REG Rec_Pointer Ptr_Val_Par;
{
REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp;
structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob);
Ptr_Val_Par->variant.var_1.Int_Comp = 5;
Next_Record->variant.var_1.Int_Comp = Ptr_Val_Par->variant.var_1.Int_Comp;
Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp;
Proc_3 (&Next_Record->Ptr_Comp); /* <-- ??????? */
if (Next_Record->Discr == Ident_1) {
Next_Record->variant.var_1.Int_Comp = 6;
Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp,
&Next_Record->variant.var_1.Enum_Comp);
Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp;
Proc_7 (Next_Record->variant.var_1.Int_Comp, 10,
&Next_Record->variant.var_1.Int_Comp);
}
else
structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp);
}
Code: Select all
Proc3((*PtrParIn->PtrComp).PtrComp);
Code: Select all
Proc3(PtrParIn->PtrComp->PtrComp);
Just curious if I'm mis-reading the QL Metacomco C and C68 code here? Anyone with a good C background that has used either of these QL C compilers have an idea if I'm right or wrong here?
Last edited by bwinkel67 on Mon Aug 08, 2022 7:10 am, edited 1 time in total.
Re: Dhrystone compiled on BBQL with Digital C SE
I must just be misunderstanding how C works here. I found the original version 1.1 of Dhrystone and it's the same as Franz Krojers with regard to Proc1():
https://github.com/Keith-S-Thompson/dhr ... hrystone.c
So sending a pointer to a pointer...i.e.:
...is the same as doing this????
I'm having difficulty wrapping my head around this...
In any case, Digital C SE forced me to do it the way of the 2nd example (i.e. do an assignment to NextRec), and so I think I found my error because I excluded the & in my call to Proc3() since I was trying to match the 1st example.
https://github.com/Keith-S-Thompson/dhr ... hrystone.c
So sending a pointer to a pointer...i.e.:
Code: Select all
Proc3(PtrParIn->PtrComp->PtrComp);
Code: Select all
RecordPtr NextRec = PtrParIn->PtrComp;
...
Proc3(&NextRec->PtrComp);
In any case, Digital C SE forced me to do it the way of the 2nd example (i.e. do an assignment to NextRec), and so I think I found my error because I excluded the & in my call to Proc3() since I was trying to match the 1st example.
Re: Dhrystone compiled on BBQL with Digital C SE
Imagine the following linked list:
(The numbers are the addresses where the structs live)
Then PtrParInt->PtrComp->PtrComp is the value of PtrComp in instance b) of the record that points to PtrComp in instance c), so "300"
NextRec in your second example is the value of PtrComp in instance a). (200)
The address of NextRec->ptrComp is then simply the value of NextRec (or, simply a pointer to instance b) ) which is something entirely different than in your first example. (again 200)
(Not quite knowing what you want makes it a bit difficult to tell you what to write)
(The numbers are the addresses where the structs live)
Code: Select all
a) b) c)
100 200 300
PtrParIn->PtrComp------------>PtrComp-------->PtrComp
Discr Discr Discr
EnumComp EnumComp EnumComp
.... ........
NextRec in your second example is the value of PtrComp in instance a). (200)
The address of NextRec->ptrComp is then simply the value of NextRec (or, simply a pointer to instance b) ) which is something entirely different than in your first example. (again 200)
(Not quite knowing what you want makes it a bit difficult to tell you what to write)
ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
Re: Dhrystone compiled on BBQL with Digital C SE
Oh, that table is a good way to work through the problem...thank you. Let me give it some thought to see if it's doing what it is supposed to.tofro wrote:Imagine the following linked list: