Welcome, Guest. Please login or register.

Author Topic: Using timer.device in C (VBCC)  (Read 4224 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline DBAlexTopic starter

  • Sr. Member
  • ****
  • Join Date: Aug 2005
  • Posts: 304
    • Show only replies by DBAlex
Using timer.device in C (VBCC)
« on: June 28, 2011, 05:52:49 PM »
Hi everyone,

Yesterday I installed VBCC, and today I have been trying to write a program to test the computation speed of a string function I wrote (Just for fun, It's not really a serious program).

To do this I needed to get the time before and after the compututation, first I tried time.h (from the C Standard Library). I found out that with VBCC clock() returns -1 with VBCC. (This is standard compliant but useless for me!).

So I did a google search and found this thread on EAB: http://eab.abime.net/showpost.php?p=761365&postcount=6

I tried the sample by Thomas Rapp, here is my actual code:
Code: [Select]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include <devices/timer.h>
#include <proto/timer.h>
#include <clib/timer_protos.h>

struct Library *TimerBase;

static struct timeval startTime;

void startup(){
GetSysTime(&startTime);
}

ULONG getMilliseconds(){
struct timeval endTime;

GetSysTime(&endTime);
SubTime(&endTime,&startTime);

return (endTime.tv_secs * 1000 + endTime.tv_micro / 1000);
}

char* realloc_strcat(char *s1, char * s2){
int len = (strlen(s1) + strlen(s2));
s1 = (char *) realloc(s1, len + 1);
strncat(s1,s2,len);
return s1;
}

int main(int argc, char * argv[]){
// Start timer
startup();

// Initialise string
int i;
char* str;
str = (char *) malloc(7);
strcpy(str,&quot;Hello &quot;);

// Call timer (1)
printf(&quot;Time 1: %lu\n&quot;,getMilliseconds());

// Computation
for(i=0; i<100; i++){
str = realloc_strcat(str,&quot;Appending string...!)&quot;);
}

// Call timer (2)
printf(&quot;Time 2: %lu\n&quot;,getMilliseconds());

}

I struggled at first to find out what to include! There is no mention of the includes needed to run the code in the EAB thread! And I couldn't find any examples of using timer.device.

It compiles fine, however I got errors about TimerBase, so I added in that code.

I compile with vbcc like so: vc strings.c -o strings -c99 -lmieee

However, when I run the code it crashes straight away! (I get the "Suspend", "Reboot" requester). The crash is caused by calling the startup() function.

Can anyone shed any light on why this may not be working?

Or provide simple examples of using timer.device to get the current milliseconds using C!

Finally, can anyone reccomend a nice Amiga programming guide/book using C for absolute beginners?

Thanks, Alex.
« Last Edit: June 28, 2011, 07:41:50 PM by DBAlex »
Machines:
- A1200, Blizzard 1260 w/ 64MB RAM, 1.2GB HD, PCMCIA WiFi, AGA w/ RGB Adapter, OS3.9
- Pegasos I, G3 600Mhz, 512MB, Radeon 9200se, 80GB HD, AmigaKit WiFi Card, MOS 1.4.5
- Mac Mini, G4 1.5ghz, 512MB (1GB Soon), Radeon 9200 64MB, 80GB HD, OSX 10.5 (Leopard)
- PCs, Laptops... *yawn*... :D
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: Using timer.device in C (VBCC)
« Reply #1 on: June 28, 2011, 06:13:40 PM »
First, try linking with libauto (-lauto). If that doesn't help you'll need to set up TimerBase by yourself, see into CreateMsgPort, CreateIORequest and OpenDevice. Once the timer.device unit is opened you can find the TimerBase from the iorequest's io_Device field [TimerBase =  ioreq->io_Device;]

At clean up perform CloseDevice, DeleteIORequest and DeleteMsgPort.

PS. It's also possible to take a shortcut with timer.device and set up a fake iorequest for OpenDevice. While strictly speaking legal it's a bit confusing for a beginner and might give you some bad ideas on how to use exec devices.
« Last Edit: June 28, 2011, 06:25:24 PM by Piru »
 

Offline DBAlexTopic starter

  • Sr. Member
  • ****
  • Join Date: Aug 2005
  • Posts: 304
    • Show only replies by DBAlex
Re: Using timer.device in C (VBCC)
« Reply #2 on: June 28, 2011, 06:39:37 PM »
Quote from: Piru;647486
First, try linking with libauto (-lauto). If that doesn't help you'll need to set up TimerBase by yourself, see into CreateMsgPort, CreateIORequest and OpenDevice. Once the timer.device unit is opened you can find the TimerBase from the iorequest's io_Device field [TimerBase =  ioreq->io_Device;]

At clean up perform CloseDevice, DeleteIORequest and DeleteMsgPort.

PS. It's also possible to take a shortcut with timer.device and set up a fake iorequest for OpenDevice. While strictly speaking legal it's a bit confusing for a beginner and might give you some bad ideas on how to use exec devices.

Hi Piru,

Some code would be helpful!

Possibly could you show me how to do that by editing my code (?). I have no idea what you mean to be honest. :-(

Also, do I have the right files included with #include? (Or, too many?)

I'm completely 100% new to Amiga programming. However i've taken a course on C programming at University.

Thanks, Alex.

EDIT: Tried linking with -lauto, the program still crashes. :-(
« Last Edit: June 28, 2011, 06:42:02 PM by DBAlex »
Machines:
- A1200, Blizzard 1260 w/ 64MB RAM, 1.2GB HD, PCMCIA WiFi, AGA w/ RGB Adapter, OS3.9
- Pegasos I, G3 600Mhz, 512MB, Radeon 9200se, 80GB HD, AmigaKit WiFi Card, MOS 1.4.5
- Mac Mini, G4 1.5ghz, 512MB (1GB Soon), Radeon 9200 64MB, 80GB HD, OSX 10.5 (Leopard)
- PCs, Laptops... *yawn*... :D
 

Offline x303

Re: Using timer.device in C (VBCC)
« Reply #3 on: June 28, 2011, 06:57:51 PM »
Quote from: DBAlex;647484

Finally, can anyone reccomend a nice Amiga programming guide/book using C for absolute beginners?

Maybe you want this: http://aminet.net/dev/c/ACM_PDF.lha

Quote
EDIT: Tried linking with -lauto, the program still crashes. :-(

Check out some of the examples on aminet. They should help a bit.
« Last Edit: June 28, 2011, 06:59:44 PM by x303 »
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: Using timer.device in C (VBCC)
« Reply #4 on: June 28, 2011, 07:03:50 PM »
Quote from: DBAlex;647489
Hi Piru,

Some code would be helpful!

Sorry, I'm too tired today. Someone else can easily cook it up.

Quote
EDIT: Tried linking with -lauto, the program still crashes. :-(

Try changing "struct Library *TimerBase;" to "extern struct Library *TimerBase;". That with -lauto might do the trick.

Your code doesn't check if malloc or realloc fail. They can fail and your code should back out nicely if they do. However, that's not the cause of the problem here, I think.
 

Offline DBAlexTopic starter

  • Sr. Member
  • ****
  • Join Date: Aug 2005
  • Posts: 304
    • Show only replies by DBAlex
Re: Using timer.device in C (VBCC)
« Reply #5 on: June 28, 2011, 07:35:15 PM »
Quote
Sorry, I'm too tired today. Someone else can easily cook it up.

Ok, no problem. Thanks for the help so far. :)

Quote
Try changing "struct Library *TimerBase;" to "extern struct Library *TimerBase;". That with -lauto might do the trick.

That gives me errors about TimerBase. The same errors I had when I didn't have TimerBase defined.

I can post these errors tomorrow if you like.

Quote
Your code doesn't check if malloc or realloc fail. They can fail and your code should back out nicely if they do. However, that's not the cause of the problem here, I think.

Ha, I knew someone would pick me up on that. Yes, it's very lazy. I just wrote this program fairly quickly from an old sample I had. I usually check for a null pointer and use exit(1) to exit from the program if malloc fails.

Without the timer code the program runs fine. So yes, It isn't the cause of error.
« Last Edit: June 28, 2011, 07:41:09 PM by DBAlex »
Machines:
- A1200, Blizzard 1260 w/ 64MB RAM, 1.2GB HD, PCMCIA WiFi, AGA w/ RGB Adapter, OS3.9
- Pegasos I, G3 600Mhz, 512MB, Radeon 9200se, 80GB HD, AmigaKit WiFi Card, MOS 1.4.5
- Mac Mini, G4 1.5ghz, 512MB (1GB Soon), Radeon 9200 64MB, 80GB HD, OSX 10.5 (Leopard)
- PCs, Laptops... *yawn*... :D
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: Using timer.device in C (VBCC)
« Reply #6 on: June 28, 2011, 08:14:21 PM »
Quote from: DBAlex;647505
Ok, no problem. Thanks for the help so far. :)



That gives me errors about TimerBase. The same errors I had when I didn't have TimerBase defined.
So VBCC does have a sucky libauto after all. Go figure.

Well this should work regardless:

Code: [Select]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/timer.h>

struct MsgPort *timer_msgport;
struct timerequest *timer_ioreq;
struct Library *TimerBase;

static int opentimer(ULONG unit){
timer_msgport = CreateMsgPort();
timer_ioreq = CreateIORequest(timer_msgport, sizeof(*timer_ioreq));
if (timer_ioreq){
if (OpenDevice(TIMERNAME, unit, (APTR) timer_ioreq, 0) == 0){
TimerBase = (APTR) timer_ioreq->tr_node.io_Device;
return 1;
}
}
return 0;
}
static void closetimer(void){
if (TimerBase){
CloseDevice((APTR) timer_ioreq);
}
DeleteIORequest(timer_ioreq);
DeleteMsgPort(timer_msgport);
TimerBase = 0;
timer_ioreq = 0;
timer_msgport = 0;
}

static struct timeval startTime;

void startup(){
GetSysTime(&startTime);
}

ULONG getMilliseconds(){
struct timeval endTime;

GetSysTime(&endTime);
SubTime(&endTime,&startTime);

return (endTime.tv_secs * 1000 + endTime.tv_micro / 1000);
}

char* realloc_strcat(char *s1, char * s2){
int len = (strlen(s1) + strlen(s2));
s1 = (char *) realloc(s1, len + 1);
if (s1 == 0){
perror(&quot;realloc&quot;);
exit(10);
}
strncat(s1,s2,len);
return s1;
}

int main(int argc, char * argv[]){
int i;
char* str;

if (atexit(closetimer) == -1){
exit(10);
}
if (opentimer(UNIT_VBLANK) == 0){
exit(10);
}

// Start timer
startup();

// Initialise string
str = (char *) malloc(7);
if (str == 0){
perror(&quot;malloc&quot;);
exit(10);
}
strcpy(str,&quot;Hello &quot;);

// Call timer (1)
printf(&quot;Time 1: %lu\n&quot;,getMilliseconds());

// Computation
for(i=0; i<100; i++){
str = realloc_strcat(str,&quot;Appending string...!)&quot;);
}

// Call timer (2)
printf(&quot;Time 2: %lu\n&quot;,getMilliseconds());

return 0;
}

Some notes:
  • I fixed the potential crashes due to malloc/realloc failing.
  • I made the code compile without C99 extensions.
  • Mixing clib and amigaos calls is quite akward. You should stick with one of them. If you mix you need to do all sort of extra trickery (such as that atexit() to ensure that amigaos resources are freed).
« Last Edit: June 28, 2011, 08:25:03 PM by Piru »
 

Offline DBAlexTopic starter

  • Sr. Member
  • ****
  • Join Date: Aug 2005
  • Posts: 304
    • Show only replies by DBAlex
Re: Using timer.device in C (VBCC)
« Reply #7 on: June 28, 2011, 09:06:59 PM »
Quote from: Piru;647518
So VBCC does have a sucky libauto after all. Go figure.

Well this should work regardless:

Code: [Select]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/timer.h>

struct MsgPort *timer_msgport;
struct timerequest *timer_ioreq;
struct Library *TimerBase;

static int opentimer(ULONG unit){
timer_msgport = CreateMsgPort();
timer_ioreq = CreateIORequest(timer_msgport, sizeof(*timer_ioreq));
if (timer_ioreq){
if (OpenDevice(TIMERNAME, unit, (APTR) timer_ioreq, 0) == 0){
TimerBase = (APTR) timer_ioreq->tr_node.io_Device;
return 1;
}
}
return 0;
}
static void closetimer(void){
if (TimerBase){
CloseDevice((APTR) timer_ioreq);
}
DeleteIORequest(timer_ioreq);
DeleteMsgPort(timer_msgport);
TimerBase = 0;
timer_ioreq = 0;
timer_msgport = 0;
}

static struct timeval startTime;

void startup(){
GetSysTime(&startTime);
}

ULONG getMilliseconds(){
struct timeval endTime;

GetSysTime(&endTime);
SubTime(&endTime,&startTime);

return (endTime.tv_secs * 1000 + endTime.tv_micro / 1000);
}

char* realloc_strcat(char *s1, char * s2){
int len = (strlen(s1) + strlen(s2));
s1 = (char *) realloc(s1, len + 1);
if (s1 == 0){
perror(&quot;realloc&quot;);
exit(10);
}
strncat(s1,s2,len);
return s1;
}

int main(int argc, char * argv[]){
int i;
char* str;

if (atexit(closetimer) == -1){
exit(10);
}
if (opentimer(UNIT_VBLANK) == 0){
exit(10);
}

// Start timer
startup();

// Initialise string
str = (char *) malloc(7);
if (str == 0){
perror(&quot;malloc&quot;);
exit(10);
}
strcpy(str,&quot;Hello &quot;);

// Call timer (1)
printf(&quot;Time 1: %lu\n&quot;,getMilliseconds());

// Computation
for(i=0; i<100; i++){
str = realloc_strcat(str,&quot;Appending string...!)&quot;);
}

// Call timer (2)
printf(&quot;Time 2: %lu\n&quot;,getMilliseconds());

return 0;
}

Some notes:
  • I fixed the potential crashes due to malloc/realloc failing.
  • I made the code compile without C99 extensions.
  • Mixing clib and amigaos calls is quite akward. You should stick with one of them. If you mix you need to do all sort of extra trickery (such as that atexit() to ensure that amigaos resources are freed).

Oh! Wow, thanks Piru! :) I will test this tomorrow.

Your final point about clib and amigaos calls: the timer code isn't my code, so not sure what you mean by that. I'm sure when I get more advanced/confident with AmigaOS programming I will understand what you mean by that.

Also I found ACM (Amiga C Manual) on Aminet which has a lot of nice samples. Also their is the OS3.9 example code which comes with the NDK which I will look at.

The RKMs are nice too, but a bit complex. (At the moment!)

Is it worth learning Intuition to create GUIs? Or should I learn a toolkit such as MUI or Reaction instead?
Machines:
- A1200, Blizzard 1260 w/ 64MB RAM, 1.2GB HD, PCMCIA WiFi, AGA w/ RGB Adapter, OS3.9
- Pegasos I, G3 600Mhz, 512MB, Radeon 9200se, 80GB HD, AmigaKit WiFi Card, MOS 1.4.5
- Mac Mini, G4 1.5ghz, 512MB (1GB Soon), Radeon 9200 64MB, 80GB HD, OSX 10.5 (Leopard)
- PCs, Laptops... *yawn*... :D
 

Offline NovaCoder

Re: Using timer.device in C (VBCC)
« Reply #8 on: June 29, 2011, 01:02:16 AM »
Hiya,

My startup code was actually listed in the original EAB thread, you could have just copied that?

Code: [Select]

void startup() {
    // Create the timer.
    timerRequest = CreateTimer(UNIT_ECLOCK);
}
 
struct timerequest *CreateTimer(ULONG theUnit)
{
    ULONG Error;
    struct timerequest *TimeReq;
    if (!(TimerPort=CreatePort(NULL,0))) {
        return NULL;
    }

    if (!(TimeReq = (struct timerequest*)(CreateExtIO(TimerPort,sizeof(struct timerequest)))))
    {
        DeletePort(TimerPort);
        return NULL;
    }

    Error = OpenDevice(TIMERNAME, theUnit, (struct IORequest*)(TimeReq), 0);
    if (Error!=0)
    {
        DeleteExtIO((struct IORequest*)(TimeReq));
        DeletePort(TimerPort);
        return NULL;
    }
    TimerBase=(struct Library*)(TimeReq->tr_node.io_Device);

    return(TimeReq);
}


I used the following declarations:

Code: [Select]

#include

    // Amiga Timer.
    struct Device *TimerBase;
    struct timerequest *timerRequest;
    struct timeval startTime;
    ULONG  timerUnit;


Seems to work ok for me using the 3.9 NDK :)
Life begins at 100 MIPS!


Nice Ports on AmiNet!
 

Offline DBAlexTopic starter

  • Sr. Member
  • ****
  • Join Date: Aug 2005
  • Posts: 304
    • Show only replies by DBAlex
Re: Using timer.device in C (VBCC)
« Reply #9 on: June 29, 2011, 04:31:18 PM »
@Piru

I tried your code today, works perfectly!

However I think C99 was still needed for the // comments.

Thanks very much for correcting me. This has given me some impetus to want to learn some more AmigaOS API programming. For instance, I noticed AmigaOS has functions to allocate memory (E.g. AllocMem, AllocVec).

Does malloc just map to these functions? Or should I use the AmigaOS versions?

@NovaCoder

:(

Yes, I see that now when looking at the post... my only excuse can be that I didn't realise what the code should look like. At the moment any AmigaOS code looks like a foreign language.
Machines:
- A1200, Blizzard 1260 w/ 64MB RAM, 1.2GB HD, PCMCIA WiFi, AGA w/ RGB Adapter, OS3.9
- Pegasos I, G3 600Mhz, 512MB, Radeon 9200se, 80GB HD, AmigaKit WiFi Card, MOS 1.4.5
- Mac Mini, G4 1.5ghz, 512MB (1GB Soon), Radeon 9200 64MB, 80GB HD, OSX 10.5 (Leopard)
- PCs, Laptops... *yawn*... :D
 

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: Using timer.device in C (VBCC)
« Reply #10 on: June 29, 2011, 05:32:36 PM »
Quote from: DBAlex;647625
@Piru
However I think C99 was still needed for the // comments.

Actually most compilers supported // comments even before C99.

Quote
I noticed AmigaOS has functions to allocate memory (E.g. AllocMem, AllocVec).

Does malloc just map to these functions?

malloc doesn't just map to those functions. Typical malloc implementations call AllocMem internally to grab large chunks of memory which they then serve to malloc callers (simplified explanation).

Also note that malloc()ed memory is released automagically at application exit. AllocMem/AllocVec memory is not.

Quote
Or should I use the AmigaOS versions?

It depends on what you do. If you use standard C libraries (stdio, stdlib etc) then you should use malloc. If you use amigaos functions you should preferably only use amigaos functions.

As said before mixing them is a bad idea.
« Last Edit: June 29, 2011, 06:01:43 PM by Piru »