SAMV71 Xplained Ultra Software Package 1.3

core_portme.c

00001 /* 
00002     File: core_portme.c
00003 */
00004 /*
00005     Author : Shay Gal-On, EEMBC
00006     Legal : TODO!
00007 */ 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include "coremark.h"
00011 #if CALLGRIND_RUN
00012 #include <valgrind/callgrind.h>
00013 #endif
00014 
00015 #if (MEM_METHOD==MEM_MALLOC)
00016 #include <malloc.h>
00017 /* Function: portable_malloc
00018     Provide malloc() functionality in a platform specific way.
00019 */
00020 void *portable_malloc(size_t size) {
00021     return malloc(size);
00022 }
00023 /* Function: portable_free
00024     Provide free() functionality in a platform specific way.
00025 */
00026 void portable_free(void *p) {
00027     free(p);
00028 }
00029 #else
00030 void *portable_malloc(size_t size) {
00031     return NULL;
00032 }
00033 void portable_free(void *p) {
00034     p=NULL;
00035 }
00036 #endif
00037 
00038 #if (SEED_METHOD==SEED_VOLATILE)
00039 #if VALIDATION_RUN
00040     volatile ee_s32 seed1_volatile=0x3415;
00041     volatile ee_s32 seed2_volatile=0x3415;
00042     volatile ee_s32 seed3_volatile=0x66;
00043 #endif
00044 #if PERFORMANCE_RUN
00045     volatile ee_s32 seed1_volatile=0x0;
00046     volatile ee_s32 seed2_volatile=0x0;
00047     volatile ee_s32 seed3_volatile=0x66;
00048 #endif
00049 #if PROFILE_RUN
00050     volatile ee_s32 seed1_volatile=0x8;
00051     volatile ee_s32 seed2_volatile=0x8;
00052     volatile ee_s32 seed3_volatile=0x8;
00053 #endif
00054     volatile ee_s32 seed4_volatile=ITERATIONS;
00055     volatile ee_s32 seed5_volatile=0;
00056 #endif
00057 /* Porting: Timing functions
00058     How to capture time and convert to seconds must be ported to whatever is supported by the platform.
00059     e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. 
00060     Sample implementation for standard time.h and windows.h definitions included.
00061 */
00062 /* Define: TIMER_RES_DIVIDER
00063     Divider to trade off timer resolution and total time that can be measured.
00064 
00065     Use lower values to increase resolution, but make sure that overflow does not occur.
00066     If there are issues with the return value overflowing, increase this value.
00067     */
00068 #if USE_CLOCK
00069     #define NSECS_PER_SEC CLOCKS_PER_SEC
00070     #define EE_TIMER_TICKER_RATE 1000
00071     #define CORETIMETYPE clock_t 
00072     #define GETMYTIME(_t) (*_t=clock())
00073     #define MYTIMEDIFF(fin,ini) ((fin)-(ini))
00074     #define TIMER_RES_DIVIDER 1
00075     #define SAMPLE_TIME_IMPLEMENTATION 1
00076 #elif defined(_MSC_VER)
00077     #define NSECS_PER_SEC 10000000
00078     #define EE_TIMER_TICKER_RATE 1000
00079     #define CORETIMETYPE FILETIME
00080     #define GETMYTIME(_t) GetSystemTimeAsFileTime(_t)
00081     #define MYTIMEDIFF(fin,ini) (((*(__int64*)&fin)-(*(__int64*)&ini))/TIMER_RES_DIVIDER)
00082     /* setting to millisces resolution by default with MSDEV */
00083     #ifndef TIMER_RES_DIVIDER
00084     #define TIMER_RES_DIVIDER 1000
00085     #endif
00086     #define SAMPLE_TIME_IMPLEMENTATION 1
00087 #elif HAS_TIME_H
00088     #define NSECS_PER_SEC 1000000000
00089     #define EE_TIMER_TICKER_RATE 1000
00090     #define CORETIMETYPE struct timespec 
00091     #define GETMYTIME(_t) clock_gettime(CLOCK_REALTIME,_t)
00092     #define MYTIMEDIFF(fin,ini) ((fin.tv_sec-ini.tv_sec)*(NSECS_PER_SEC/TIMER_RES_DIVIDER)+(fin.tv_nsec-ini.tv_nsec)/TIMER_RES_DIVIDER)
00093     /* setting to 1/1000 of a second resolution by default with linux */
00094     #ifndef TIMER_RES_DIVIDER
00095     #define TIMER_RES_DIVIDER 1000000
00096     #endif
00097     #define SAMPLE_TIME_IMPLEMENTATION 1
00098 #else
00099     #define SAMPLE_TIME_IMPLEMENTATION 0
00100 #endif
00101 #define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER)
00102 
00103 #if SAMPLE_TIME_IMPLEMENTATION
00104 /** Define Host specific (POSIX), or target specific global time variables. */
00105 static CORETIMETYPE start_time_val, stop_time_val;
00106 
00107 /* Function: start_time
00108     This function will be called right before starting the timed portion of the benchmark.
00109 
00110     Implementation may be capturing a system timer (as implemented in the example code) 
00111     or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0.
00112 */
00113 void start_time(void) {
00114     GETMYTIME(&start_time_val );      
00115 #if CALLGRIND_RUN
00116     CALLGRIND_START_INSTRUMENTATION
00117 #endif
00118 #if MICA
00119     asm volatile("int3");/*1 */
00120 #endif
00121 }
00122 /* Function: stop_time
00123     This function will be called right after ending the timed portion of the benchmark.
00124 
00125     Implementation may be capturing a system timer (as implemented in the example code) 
00126     or other system parameters - e.g. reading the current value of cpu cycles counter.
00127 */
00128 void stop_time(void) {
00129 #if CALLGRIND_RUN
00130      CALLGRIND_STOP_INSTRUMENTATION 
00131 #endif
00132 #if MICA
00133     asm volatile("int3");/*1 */
00134 #endif
00135     GETMYTIME(&stop_time_val );      
00136 }
00137 /* Function: get_time
00138     Return an abstract "ticks" number that signifies time on the system.
00139     
00140     Actual value returned may be cpu cycles, milliseconds or any other value,
00141     as long as it can be converted to seconds by <time_in_secs>.
00142     This methodology is taken to accomodate any hardware or simulated platform.
00143     The sample implementation returns millisecs by default, 
00144     and the resolution is controlled by <TIMER_RES_DIVIDER>
00145 */
00146 CORE_TICKS get_time(void) {
00147     CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val));
00148     return elapsed;
00149 }
00150 /* Function: time_in_secs
00151     Convert the value returned by get_time to seconds.
00152 
00153     The <secs_ret> type is used to accomodate systems with no support for floating point.
00154     Default implementation implemented by the EE_TICKS_PER_SEC macro above.
00155 */
00156 secs_ret time_in_secs(CORE_TICKS ticks) {
00157     secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC;
00158     return retval;
00159 }
00160 #else 
00161 #error "Please implement timing functionality in core_portme.c"
00162 #endif /* SAMPLE_TIME_IMPLEMENTATION */
00163 
00164 ee_u32 default_num_contexts=MULTITHREAD;
00165 
00166 /* Function: portable_init
00167     Target specific initialization code 
00168     Test for some common mistakes.
00169 */
00170 void portable_init(core_portable *p, int *argc, char *argv[])
00171 {
00172 #if PRINT_ARGS
00173     int i;
00174     for (i=0; i<*argc; i++) {
00175         ee_printf("Arg[%d]=%s\n",i,argv[i]);
00176     }
00177 #endif
00178     if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {
00179         ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n");
00180     }
00181     if (sizeof(ee_u32) != 4) {
00182         ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n");
00183     }
00184 #if (MAIN_HAS_NOARGC && (SEED_METHOD==SEED_ARG))
00185     ee_printf("ERROR! Main has no argc, but SEED_METHOD defined to SEED_ARG!\n");
00186 #endif
00187     
00188 #if (MULTITHREAD>1) && (SEED_METHOD==SEED_ARG)
00189     int nargs=*argc,i;
00190     if ((nargs>1) && (*argv[1]=='M')) {
00191         default_num_contexts=parseval(argv[1]+1);
00192         if (default_num_contexts>MULTITHREAD)
00193             default_num_contexts=MULTITHREAD;
00194         /* Shift args since first arg is directed to the portable part and not to coremark main */
00195         --nargs;
00196         for (i=1; i<nargs; i++)
00197             argv[i]=argv[i+1];
00198         *argc=nargs;
00199     }
00200 #endif /* sample of potential platform specific init via command line, reset the number of contexts being used if first argument is M<n>*/
00201     p->portable_id=1;
00202 }
00203 /* Function: portable_fini
00204     Target specific final code 
00205 */
00206 void portable_fini(core_portable *p)
00207 {
00208     p->portable_id=0;
00209 }
00210 
00211 #if (MULTITHREAD>1)
00212 
00213 /* Function: core_start_parallel
00214     Start benchmarking in a parallel context.
00215     
00216     Three implementations are provided, one using pthreads, one using fork and shared mem, and one using fork and sockets.
00217     Other implementations using MCAPI or other standards can easily be devised.
00218 */
00219 /* Function: core_stop_parallel
00220     Stop a parallel context execution of coremark, and gather the results.
00221     
00222     Three implementations are provided, one using pthreads, one using fork and shared mem, and one using fork and sockets.
00223     Other implementations using MCAPI or other standards can easily be devised.
00224 */
00225 #if USE_PTHREAD
00226 ee_u8 core_start_parallel(core_results *res) {
00227     return (ee_u8)pthread_create(&(res->port.thread),NULL,iterate,(void *)res);
00228 }
00229 ee_u8 core_stop_parallel(core_results *res) {
00230     void *retval;
00231     return (ee_u8)pthread_join(res->port.thread,&retval);
00232 }
00233 #elif USE_FORK
00234 static int key_id=0;
00235 ee_u8 core_start_parallel(core_results *res) {
00236     key_t key=4321+key_id;
00237     key_id++;
00238     res->port.pid=fork();
00239     res->port.shmid=shmget(key, 8, IPC_CREAT | 0666);
00240     if (res->port.shmid<0) {
00241         ee_printf("ERROR in shmget!\n");
00242     }
00243     if (res->port.pid==0) {
00244         iterate(res);
00245         res->port.shm=shmat(res->port.shmid, NULL, 0);
00246         /* copy the validation values to the shared memory area  and quit*/
00247         if (res->port.shm == (char *) -1) {
00248             ee_printf("ERROR in child shmat!\n");
00249         } else {
00250             memcpy(res->port.shm,&(res->crc),8);
00251             shmdt(res->port.shm);
00252         }
00253         exit(0);
00254     }
00255     return 1;
00256 }
00257 ee_u8 core_stop_parallel(core_results *res) {
00258     int status;
00259     pid_t wpid = waitpid(res->port.pid,&status,WUNTRACED);
00260     if (wpid != res->port.pid) {
00261         ee_printf("ERROR waiting for child.\n");
00262         if (errno == ECHILD) ee_printf("errno=No such child %d\n",res->port.pid);
00263         if (errno == EINTR) ee_printf("errno=Interrupted\n");
00264         return 0;
00265     }
00266     /* after process is done, get the values from the shared memory area */
00267     res->port.shm=shmat(res->port.shmid, NULL, 0);
00268     if (res->port.shm == (char *) -1) {
00269         ee_printf("ERROR in parent shmat!\n");
00270         return 0;
00271     } 
00272     memcpy(&(res->crc),res->port.shm,8);
00273     shmdt(res->port.shm);
00274     return 1;
00275 }
00276 #elif USE_SOCKET
00277 static int key_id=0;
00278 ee_u8 core_start_parallel(core_results *res) {
00279     int bound, buffer_length=8;
00280     res->port.sa.sin_family = AF_INET;
00281     res->port.sa.sin_addr.s_addr = htonl(0x7F000001);
00282     res->port.sa.sin_port = htons(7654+key_id);
00283     key_id++;
00284     res->port.pid=fork();
00285     if (res->port.pid==0) { /* benchmark child */
00286         iterate(res);
00287         res->port.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00288         if (-1 == res->port.sock) /* if socket failed to initialize, exit */   {
00289             ee_printf("Error Creating Socket");
00290         } else {
00291             int bytes_sent = sendto(res->port.sock, &(res->crc), buffer_length, 0,(struct sockaddr*)&(res->port.sa), sizeof (struct sockaddr_in));
00292             if (bytes_sent < 0)
00293                 ee_printf("Error sending packet: %s\n", strerror(errno));
00294             close(res->port.sock); /* close the socket */
00295         }
00296         exit(0);
00297     } 
00298     /* parent process, open the socket */
00299     res->port.sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
00300     bound = bind(res->port.sock,(struct sockaddr*)&(res->port.sa), sizeof(struct sockaddr));
00301     if (bound < 0)
00302         ee_printf("bind(): %s\n",strerror(errno));
00303     return 1;
00304 }
00305 ee_u8 core_stop_parallel(core_results *res) {
00306     int status;
00307     int fromlen=sizeof(struct sockaddr);
00308     int recsize = recvfrom(res->port.sock, &(res->crc), 8, 0, (struct sockaddr*)&(res->port.sa), &fromlen);
00309     if (recsize < 0) {
00310         ee_printf("Error in receive: %s\n", strerror(errno));
00311         return 0;
00312     }
00313     pid_t wpid = waitpid(res->port.pid,&status,WUNTRACED);
00314     if (wpid != res->port.pid) {
00315         ee_printf("ERROR waiting for child.\n");
00316         if (errno == ECHILD) ee_printf("errno=No such child %d\n",res->port.pid);
00317         if (errno == EINTR) ee_printf("errno=Interrupted\n");
00318         return 0;
00319     }
00320     return 1;
00321 }
00322 #else /* no standard multicore implementation */
00323 #error "Please implement multicore functionality in core_portme.c to use multiple contexts."
00324 #endif /* multithread implementations */
00325 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines