source: soft/giet_vm/applications/coremark/core_list_join.c @ 753

Last change on this file since 753 was 753, checked in by cfuguet, 8 years ago

Introducing the coremark benchmark

File size: 14.3 KB
Line 
1/*
2Author : Shay Gal-On, EEMBC
3
4This file is part of  EEMBC(R) and CoreMark(TM), which are Copyright (C) 2009
5All rights reserved.                           
6
7EEMBC CoreMark Software is a product of EEMBC and is provided under the terms of the
8CoreMark License that is distributed with the official EEMBC COREMARK Software release.
9If you received this EEMBC CoreMark Software without the accompanying CoreMark License,
10you must discontinue use and download the official release from www.coremark.org. 
11
12Also, if you are publicly displaying scores generated from the EEMBC CoreMark software,
13make sure that you are in compliance with Run and Reporting rules specified in the accompanying readme.txt file.
14
15EEMBC
164354 Town Center Blvd. Suite 114-200
17El Dorado Hills, CA, 95762
18*/ 
19
20#include "coremark.h"
21/*
22Topic: Description
23        Benchmark using a linked list.
24
25        Linked list is a common data structure used in many applications.
26       
27        For our purposes, this will excercise the memory units of the processor.
28        In particular, usage of the list pointers to find and alter data.
29       
30        We are not using Malloc since some platforms do not support this library.
31       
32        Instead, the memory block being passed in is used to create a list,
33        and the benchmark takes care not to add more items then can be
34        accomodated by the memory block. The porting layer will make sure
35        that we have a valid memory block.
36       
37        All operations are done in place, without using any extra memory.
38       
39        The list itself contains list pointers and pointers to data items.
40        Data items contain the following:
41       
42        idx - An index that captures the initial order of the list.
43        data - Variable data initialized based on the input parameters. The 16b are divided as follows:
44        o Upper 8b are backup of original data.
45        o Bit 7 indicates if the lower 7 bits are to be used as is or calculated.
46        o Bits 0-2 indicate type of operation to perform to get a 7b value.
47        o Bits 3-6 provide input for the operation.
48       
49*/
50
51/* local functions */
52
53list_head *core_list_find(list_head *list,list_data *info);
54list_head *core_list_reverse(list_head *list);
55list_head *core_list_remove(list_head *item);
56list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified);
57list_head *core_list_insert_new(list_head *insert_point
58        , list_data *info, list_head **memblock, list_data **datablock
59        , list_head *memblock_end, list_data *datablock_end);
60typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res);
61list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res);
62
63ee_s16 calc_func(ee_s16 *pdata, core_results *res) {
64        ee_s16 data=*pdata;
65        ee_s16 retval;
66        ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */
67        if (optype) /* if cached, use cache */
68                return (data & 0x007f);
69        else { /* otherwise calculate and cache the result */
70                ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */
71                ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */
72                dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */
73                switch (flag) {
74                        case 0:
75                                if (dtype<0x22) /* set min period for bit corruption */
76                                        dtype=0x22;
77                                retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc);
78                                if (res->crcstate==0)
79                                        res->crcstate=retval;
80                                break;
81                        case 1:
82                                retval=core_bench_matrix(&(res->mat),dtype,res->crc);
83                                if (res->crcmatrix==0)
84                                        res->crcmatrix=retval;
85                                break;
86                        default:
87                                retval=data;
88                                break;
89                }
90                res->crc=crcu16(retval,res->crc);
91                retval &= 0x007f; 
92                *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */
93                return retval;
94        }
95}
96/* Function: cmp_complex
97        Compare the data item in a list cell.
98
99        Can be used by mergesort.
100*/
101ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) {
102        ee_s16 val1=calc_func(&(a->data16),res);
103        ee_s16 val2=calc_func(&(b->data16),res);
104        return val1 - val2;
105}
106
107/* Function: cmp_idx
108        Compare the idx item in a list cell, and regen the data.
109
110        Can be used by mergesort.
111*/
112ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) {
113        if (res==NULL) {
114                a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8));
115                b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8));
116        }
117        return a->idx - b->idx;
118}
119
120void copy_info(list_data *to,list_data *from) {
121        to->data16=from->data16;
122        to->idx=from->idx;
123}
124
125/* Benchmark for linked list:
126        - Try to find multiple data items.
127        - List sort
128        - Operate on data from list (crc)
129        - Single remove/reinsert
130        * At the end of this function, the list is back to original state
131*/
132ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) {
133        ee_u16 retval=0;
134        ee_u16 found=0,missed=0;
135        list_head *list=res->list;
136        ee_s16 find_num=res->seed3;
137        list_head *this_find;
138        list_head *finder, *remover;
139        list_data info;
140        ee_s16 i;
141
142        info.idx=finder_idx;
143        /* find <find_num> values in the list, and change the list each time (reverse and cache if value found) */
144        for (i=0; i<find_num; i++) {
145                info.data16= (i & 0xff) ;
146                this_find=core_list_find(list,&info);
147                list=core_list_reverse(list);
148                if (this_find==NULL) {
149                        missed++;
150                        retval+=(list->next->info->data16 >> 8) & 1;
151                }
152                else {
153                        found++;
154                        if (this_find->info->data16 & 0x1) /* use found value */
155                                retval+=(this_find->info->data16 >> 9) & 1;
156                        /* and cache next item at the head of the list (if any) */
157                        if (this_find->next != NULL) {
158                                finder = this_find->next;
159                                this_find->next = finder->next;
160                                finder->next=list->next;
161                                list->next=finder;
162                        }
163                }
164                if (info.idx>=0)
165                        info.idx++;
166#if CORE_DEBUG
167        ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found);
168#endif
169        }
170        retval+=found*4-missed;
171        /* sort the list by data content and remove one item*/
172        if (finder_idx>0)
173                list=core_list_mergesort(list,cmp_complex,res);
174        remover=core_list_remove(list->next);
175        /* CRC data content of list from location of index N forward, and then undo remove */
176        finder=core_list_find(list,&info);
177        if (!finder)
178                finder=list->next;
179        while (finder) {
180                retval=crc16(list->info->data16,retval);
181                finder=finder->next;
182        }
183#if CORE_DEBUG
184        ee_printf("List sort 1: %04x\n",retval);
185#endif
186        remover=core_list_undo_remove(remover,list->next);
187        /* sort the list by index, in effect returning the list to original state */
188        list=core_list_mergesort(list,cmp_idx,NULL);
189        /* CRC data content of list */
190        finder=list->next;
191        while (finder) {
192                retval=crc16(list->info->data16,retval);
193                finder=finder->next;
194        }
195#if CORE_DEBUG
196        ee_printf("List sort 2: %04x\n",retval);
197#endif
198        return retval;
199}
200/* Function: core_list_init
201        Initialize list with data.
202
203        Parameters:
204        blksize - Size of memory to be initialized.
205        memblock - Pointer to memory block.
206        seed -  Actual values chosen depend on the seed parameter.
207                The seed parameter MUST be supplied from a source that cannot be determined at compile time
208
209        Returns:
210        Pointer to the head of the list.
211
212*/
213list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) {
214        /* calculated pointers for the list */
215        ee_u32 per_item=16+sizeof(struct list_data_s);
216        ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */
217        list_head *memblock_end=memblock+size;
218        list_data *datablock=(list_data *)(memblock_end);
219        list_data *datablock_end=datablock+size;
220        /* some useful variables */
221        ee_u32 i;
222        list_head *finder,*list=memblock;
223        list_data info;
224
225        /* create a fake items for the list head and tail */
226        list->next=NULL;
227        list->info=datablock;
228        list->info->idx=0x0000;
229        list->info->data16=(ee_s16)0x8080;
230        memblock++;
231        datablock++;
232        info.idx=0x7fff;
233        info.data16=(ee_s16)0xffff;
234        core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end);
235       
236        /* then insert size items */
237        for (i=0; i<size; i++) {
238                ee_u16 datpat=((ee_u16)(seed^i) & 0xf);
239                ee_u16 dat=(datpat<<3) | (i&0x7); /* alternate between algorithms */
240                info.data16=(dat<<8) | dat;             /* fill the data with actual data and upper bits with rebuild value */
241                core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end);
242        }
243        /* and now index the list so we know initial seed order of the list */
244        finder=list->next;
245        i=1;
246        while (finder->next!=NULL) {
247                if (i<size/5) /* first 20% of the list in order */
248                        finder->info->idx=i++;
249                else { 
250                        ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */
251                        finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */
252                }
253                finder=finder->next;
254        }
255        list = core_list_mergesort(list,cmp_idx,NULL);
256#if CORE_DEBUG
257        ee_printf("Initialized list:\n");
258        finder=list;
259        while (finder) {
260                ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16);
261                finder=finder->next;
262        }
263        ee_printf("\n");
264#endif
265        return list;
266}
267
268/* Function: core_list_insert
269        Insert an item to the list
270
271        Parameters:
272        insert_point - where to insert the item.
273        info - data for the cell.
274        memblock - pointer for the list header
275        datablock - pointer for the list data
276        memblock_end - end of region for list headers
277        datablock_end - end of region for list data
278
279        Returns:
280        Pointer to new item.
281*/
282list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock
283        , list_head *memblock_end, list_data *datablock_end) {
284        list_head *newitem;
285       
286        if ((*memblock+1) >= memblock_end)
287                return NULL;
288        if ((*datablock+1) >= datablock_end)
289                return NULL;
290               
291        newitem=*memblock;
292        (*memblock)++;
293        newitem->next=insert_point->next;
294        insert_point->next=newitem;
295       
296        newitem->info=*datablock;
297        (*datablock)++;
298        copy_info(newitem->info,info);
299       
300        return newitem;
301}
302
303/* Function: core_list_remove
304        Remove an item from the list.
305
306        Operation:
307        For a singly linked list, remove by copying the data from the next item
308        over to the current cell, and unlinking the next item.
309
310        Note:
311        since there is always a fake item at the end of the list, no need to check for NULL.
312
313        Returns:
314        Removed item.
315*/
316list_head *core_list_remove(list_head *item) {
317        list_data *tmp;
318        list_head *ret=item->next;
319        /* swap data pointers */
320        tmp=item->info;
321        item->info=ret->info;
322        ret->info=tmp;
323        /* and eliminate item */
324        item->next=item->next->next;
325        ret->next=NULL;
326        return ret;
327}
328
329/* Function: core_list_undo_remove
330        Undo a remove operation.
331
332        Operation:
333        Since we want each iteration of the benchmark to be exactly the same,
334        we need to be able to undo a remove.
335        Link the removed item back into the list, and switch the info items.
336
337        Parameters:
338        item_removed - Return value from the <core_list_remove>
339        item_modified - List item that was modified during <core_list_remove>
340
341        Returns:
342        The item that was linked back to the list.
343       
344*/
345list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) {
346        list_data *tmp;
347        /* swap data pointers */
348        tmp=item_removed->info;
349        item_removed->info=item_modified->info;
350        item_modified->info=tmp;
351        /* and insert item */
352        item_removed->next=item_modified->next;
353        item_modified->next=item_removed;
354        return item_removed;
355}
356
357/* Function: core_list_find
358        Find an item in the list
359
360        Operation:
361        Find an item by idx (if not 0) or specific data value
362
363        Parameters:
364        list - list head
365        info - idx or data to find
366
367        Returns:
368        Found item, or NULL if not found.
369*/
370list_head *core_list_find(list_head *list,list_data *info) {
371        if (info->idx>=0) {
372                while (list && (list->info->idx != info->idx))
373                        list=list->next;
374                return list;
375        } else {
376                while (list && ((list->info->data16 & 0xff) != info->data16))
377                        list=list->next;
378                return list;
379        }
380}
381/* Function: core_list_reverse
382        Reverse a list
383
384        Operation:
385        Rearrange the pointers so the list is reversed.
386
387        Parameters:
388        list - list head
389        info - idx or data to find
390
391        Returns:
392        Found item, or NULL if not found.
393*/
394
395list_head *core_list_reverse(list_head *list) {
396        list_head *next=NULL, *tmp;
397        while (list) {
398                tmp=list->next;
399                list->next=next;
400                next=list;
401                list=tmp;
402        }
403        return next;
404}
405/* Function: core_list_mergesort
406        Sort the list in place without recursion.
407
408        Description:
409        Use mergesort, as for linked list this is a realistic solution.
410        Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm.
411        The sort can either return the list to original order (by idx) ,
412        or use the data item to invoke other other algorithms and change the order of the list.
413
414        Parameters:
415        list - list to be sorted.
416        cmp - cmp function to use
417
418        Returns:
419        New head of the list.
420
421        Note:
422        We have a special header for the list that will always be first,
423        but the algorithm could theoretically modify where the list starts.
424
425 */
426list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) {
427    list_head *p, *q, *e, *tail;
428    ee_s32 insize, nmerges, psize, qsize, i;
429
430    insize = 1;
431
432    while (1) {
433        p = list;
434        list = NULL;
435        tail = NULL;
436
437        nmerges = 0;  /* count number of merges we do in this pass */
438
439        while (p) {
440            nmerges++;  /* there exists a merge to be done */
441            /* step `insize' places along from p */
442            q = p;
443            psize = 0;
444            for (i = 0; i < insize; i++) {
445                psize++;
446                            q = q->next;
447                if (!q) break;
448            }
449
450            /* if q hasn't fallen off end, we have two lists to merge */
451            qsize = insize;
452
453            /* now we have two lists; merge them */
454            while (psize > 0 || (qsize > 0 && q)) {
455
456                                /* decide whether next element of merge comes from p or q */
457                                if (psize == 0) {
458                                    /* p is empty; e must come from q. */
459                                    e = q; q = q->next; qsize--;
460                                } else if (qsize == 0 || !q) {
461                                    /* q is empty; e must come from p. */
462                                    e = p; p = p->next; psize--;
463                                } else if (cmp(p->info,q->info,res) <= 0) {
464                                    /* First element of p is lower (or same); e must come from p. */
465                                    e = p; p = p->next; psize--;
466                                } else {
467                                    /* First element of q is lower; e must come from q. */
468                                    e = q; q = q->next; qsize--;
469                                }
470
471                        /* add the next element to the merged list */
472                                if (tail) {
473                                    tail->next = e;
474                                } else {
475                                    list = e;
476                                }
477                                tail = e;
478                }
479
480                        /* now p has stepped `insize' places along, and q has too */
481                        p = q;
482        }
483               
484            tail->next = NULL;
485
486        /* If we have done only one merge, we're finished. */
487        if (nmerges <= 1)   /* allow for nmerges==0, the empty list case */
488            return list;
489
490        /* Otherwise repeat, merging lists twice the size */
491        insize *= 2;
492    }
493#if COMPILER_REQUIRES_SORT_RETURN
494        return list;
495#endif
496}
Note: See TracBrowser for help on using the repository browser.