source: sources/src/gen_code.cc @ 60

Last change on this file since 60 was 60, checked in by meunier, 7 years ago
  • Intégration des modifications de Clément, qui a intégré la version parallélisée de systemcass faite par Manuel.
File size: 20.8 KB
Line 
1/*------------------------------------------------------------\
2  |                                                             |
3  | Tool    :                  systemcass                       |
4  |                                                             |
5  | File    :                 gen_code.cc                       |
6  |                                                             |
7  | Author  :                 Taktak Sami                       |
8  |                           Buchmann Richard                  |
9  |                                                             |
10  | Date    :                   09_07_2004                      |
11  |                                                             |
12  \------------------------------------------------------------*/
13
14/*
15 * This file is part of the Disydent Project
16 * Copyright (C) Laboratoire LIP6 - Département ASIM
17 * Universite Pierre et Marie Curie
18 *
19 * Home page          : http://www-asim.lip6.fr/disydent
20 * E-mail             : mailto:richard.buchmann@lip6.fr
21 *
22 * This library is free software; you  can redistribute it and/or modify it
23 * under the terms  of the GNU Library General Public  License as published
24 * by the Free Software Foundation; either version 2 of the License, or (at
25 * your option) any later version.
26 *
27 * Disydent is distributed  in the hope  that it  will be
28 * useful, but WITHOUT  ANY WARRANTY; without even the  implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
30 * Public License for more details.
31 *
32 * You should have received a copy  of the GNU General Public License along
33 * with the GNU C Library; see the  file COPYING. If not, write to the Free
34 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 */
36
37#if defined(__linux__)
38#include <linux/limits.h>
39#elif defined(WIN32)
40#include <windows.h>
41#elif defined(__MACH__)
42#include <sys/syslimits.h>
43#endif
44
45#include <unistd.h>
46#include <cstring>
47#include <cstdio>
48#include <cstdlib>
49#include <iostream>
50#include <fstream>
51#ifdef _OPENMP
52#include <omp.h>
53#endif
54
55#include "internal.h"
56#include "gen_code.h"
57#include "sc_module.h"
58#include "sc_ver.h"
59#include "process_dependency.h"
60
61#ifdef HAVE_CONFIG_H
62#include "config.h"
63#endif
64
65#define casc_cflags GENERATED_MODULE_CFLAGS
66
67// Enable CPP call, this is useful for typeinfo-enabled classes
68#define CPP_CALL
69
70using namespace std;
71
72namespace sc_core {
73
74static void PrintCall(std::ostream &, const method_process_t &);
75static void open_temp(std::ofstream &, char *);
76typedef void (*CASC_ENTRY_FUNC) (void *);
77typedef union {
78    unsigned long long int integer;
79    SC_ENTRY_FUNC pmf;
80    CASC_ENTRY_FUNC pf;
81} fct;
82
83
84const char * get_pmf_type() {
85    switch (sizeof(SC_ENTRY_FUNC)) {
86        case 4:
87            // G4 pointer-to-member-function style
88            return "unsigned long int";
89        case 8:
90            // PC pointer-to-member-function style
91            return "unsigned long long int";
92        default:
93            cerr <<
94                "Internal Error : Unsupported pointer-to-member-function"
95                "(size: " << sizeof(SC_ENTRY_FUNC) << ").\n"
96                "Please try --nodynamiclink option.\n";
97            exit(21072009);
98    };
99}
100
101
102static ostream & operator <<(ostream & o, const SC_ENTRY_FUNC & f) {
103    register fct p;
104    p.integer = 0;
105    p.pmf = f;
106    return o << "0x" << hex << p.integer << "ULL";
107}
108
109
110static void PrintCall(std::ostream & o, const method_process_t & m) {
111    SC_ENTRY_FUNC func = m.func;
112    if (print_schedule) {
113        o << "    fprintf(stderr,\"evaluation de " << m.module->name() << "->" << m.name << "()\\n\");\n";
114    }
115    o << " p.integer = " << func << ";\n";
116#ifdef CPP_CALL
117    o << " (((sc_module*)(" << m.module << "))->*(p.pmf)) (); /* " << m.module->name() << "->" << m.name << "() */\n";
118#else
119    o << " p.pf((void *)" << m.module << "); /* " << m.module->name() << "->" << m.name << "() */\n";
120#endif
121}
122
123
124static bool is_exist(const char * temp) {
125    ifstream o;
126    o.open(temp, ios::in);
127    if (o.is_open() == false) {
128        return false;
129    }
130    if (o.peek() == -1) {
131        return false;
132    }
133    return true;
134}
135
136
137static void open_temp(ofstream & o, char * temp) {
138    /*
139       srand (time (NULL));
140       int r = rand () % 1000;
141       */
142    pid_t pid = getpid();
143    int r = -1;
144    do {
145        sprintf(temp, "%s/scheduling-%d-%x.cc", temporary_dir, pid, ++r);
146    } while (is_exist(temp));
147
148    o.open(temp, ios::out);
149    if (o.is_open() == false) {
150        cerr << "Error : Unable to open a file to write scheduling code.\n";
151        exit(30032005);
152    }
153#ifdef CONFIG_DEBUG
154    cerr << "opened temporary filename : " << temp << "\n";
155#endif
156    sprintf(temp, "scheduling-%d-%x", pid, r++);
157}
158
159
160static char * gen_transition(ofstream & o, method_process_list_t & transition_func_list) {
161    // transitions
162    o << "\ninline void transition(void)\n{\n";
163    if (transition_func_list.empty() == false) {
164        o << " /* fonctions de transition */\n" << " register fct p;\n";
165        method_process_list_t::iterator mm;
166        for (mm = transition_func_list.begin(); mm != transition_func_list.end(); ++mm) {
167            PrintCall(o, **mm);
168        }
169    }
170    o << "}\n";
171}
172
173
174static char * gen_moore(ofstream & o, method_process_list_t & moore_func_list) {
175    // Moore generations (sequential functions)
176    o << "\ninline void moore_generation (void)\n{\n";
177    if (moore_func_list.empty() == false) {
178        o << "  /* fonctions de generation de Moore */\n"
179            << " register fct p;\n";
180        method_process_list_t::reverse_iterator mm;
181        for (mm = moore_func_list.rbegin();
182                mm != moore_func_list.rend(); ++mm) {
183            PrintCall(o, **mm);
184        }
185    }
186    o << " \n}\n";
187}
188
189
190static char * gen_mealy(ofstream & o, strong_component_list_t & strongcomponents) {
191    // Mealy generations (combinational functions only)
192    o << "\nextern void mealy_generation (void)\n{\n";
193    if (strongcomponents.empty()) {
194        return NULL;
195    }
196    o << "  register fct p;\n" << "\n\n  /* fonctions de mealy */\n";
197#ifdef NO_STATIC_SCHEDULE
198    o << "\n  do {\n    unstable = 0;\n";
199#endif
200    strong_component_list_t::iterator ss;
201    for (ss = strongcomponents.begin(); ss != strongcomponents.end(); ++ss) {
202        if ((*ss)->size() == 1) {
203            /* un seul element dans le strong component */
204            method_process_t *m = (method_process_t *) (*((*ss)->begin()));
205            PrintCall(o, *m);
206            continue;
207        }
208        else {
209            /* plusieurs elements dans le strong component */
210#ifndef NO_STATIC_SCHEDULE
211            o << "\n  do {\n    unstable = 0;\n";
212#endif
213            component_list_t::reverse_iterator rev_mm;
214            for (rev_mm = (*ss)->rbegin(); rev_mm != (*ss)->rend(); ++rev_mm) {
215                method_process_t * m = (method_process_t *) * rev_mm;
216                PrintCall(o, *m);
217            }
218#ifndef NO_STATIC_SCHEDULE
219            o << "  } while ( unstable );\n\n";
220#endif
221        }
222    }
223#ifdef NO_STATIC_SCHEDULE
224    o << "  } while ( unstable );\n\n";
225#else
226    o << "\tunstable = 0;\n";
227#endif
228}
229
230
231static char * gen_mealy(ofstream & o, ProcessDependencyList & mealy_func_list) {
232    // Mealy generations (combinational functions only)
233    o << "\nextern void mealy_generation (void)\n{\n";
234    o << "  register fct p;\n" << "\n\n  /* fonctions de mealy */\n";
235    ProcessDependencyList::iterator it;
236    for (it = mealy_func_list.begin(); it != mealy_func_list.end(); ++it) {
237        const method_process_t * m = *it;
238        PrintCall(o, *m);
239    }
240}
241
242
243char * gen_scheduling_code_for_dynamic_link(method_process_list_t &
244        transition_func_list,
245        method_process_list_t &
246        moore_func_list,
247        strong_component_list_t *
248        strongcomponents) {
249    if (dump_stage) {
250        cerr << "Generating C code for scheduling...\n";
251    }
252
253    // open temporary file
254    ofstream o;
255    char base_name[PATH_MAX];
256    open_temp(o, base_name);
257
258    if (!o.good()) {
259        perror("scheduling: open file\n");
260        exit(-1);
261    }
262
263    o << "// generated by " << sc_version() << endl
264        << "#include <casc.h>\n\n" << "#include <cstdio>\n\n"
265        //  << "#include <iostream>\n\n"
266        << "namespace sc_core {\n"
267        << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
268        << " typedef void (*CASC_ENTRY_FUNC)(void *);\n";
269
270    const char * pmf_type = get_pmf_type();
271
272    o << " typedef union { "
273        << pmf_type
274        << " integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
275
276    gen_transition(o, transition_func_list);
277    gen_moore(o, moore_func_list);
278    if (strongcomponents != NULL) {
279        gen_mealy      (o, *strongcomponents);
280    }
281
282    o << " \n}\n";
283    o << "\n} // end of sc_core namespace\n";
284
285    o.flush();
286    o.close();
287
288    // add "cc" extension
289    char file_name[PATH_MAX];
290    strncpy(file_name, base_name, PATH_MAX);
291    file_name[strlen(base_name)] = '\0';
292    strcat(file_name, ".cc");
293    rename(base_name, file_name);
294
295    if (edit_schedule) {
296        run_schedule_editor(file_name);
297    }
298
299    if (dump_stage) {
300        cerr << "Generating C code for scheduling done.\n";
301    }
302
303    return strdup(base_name);
304}
305
306
307char * gen_scheduling_code_for_dynamic_link(method_process_list_t &
308        transition_func_list,
309        method_process_list_t &
310        moore_func_list,
311        ProcessDependencyList &
312        mealy_func_list) {
313    if (dump_stage) {
314        cerr << "Generating C code for scheduling...\n";
315    }
316
317    // open temporary file
318    ofstream o;
319    char base_name[PATH_MAX];
320    open_temp(o, base_name);
321
322    if (!o.good()) {
323        perror("scheduling: open file\n");
324        exit(-1);
325    }
326
327    o << "// generated by " << sc_version() << endl
328        << "#include <casc.h>\n\n" << "#include <cstdio>\n\n"
329        << "namespace sc_core {\n"
330        << " typedef void (sc_module::*SC_ENTRY_FUNC)();\n"
331        << " typedef void (*CASC_ENTRY_FUNC)(void *);\n"
332        <<
333        " typedef union { unsigned long long int integer; SC_ENTRY_FUNC pmf; CASC_ENTRY_FUNC pf; } fct;\n";
334
335    gen_transition(o, transition_func_list);
336    gen_moore(o, moore_func_list);
337    gen_mealy(o, mealy_func_list);
338
339    o << "\n}\n";
340    o << "\n} // end of sc_core namespace\n";
341
342    o.flush();
343    o.close();
344
345    // add "cc" extension
346    char file_name[PATH_MAX];
347    strncpy(file_name, base_name, PATH_MAX);
348    file_name[strlen(base_name)] = '\0';
349    strcat(file_name, ".cc");
350    rename(base_name, file_name);
351
352    if (edit_schedule) {
353        run_schedule_editor(file_name);
354    }
355
356    if (dump_stage) {
357        cerr << "Generating C code for scheduling done.\n";
358    }
359
360    return strdup(base_name);
361}
362
363
364/* base_name est la base du nom du fichier C++
365 * casc_cflags est une string qui correspond à $(INCLUDE) d'un Makefile
366 */
367void compile_code(const char * base_name, const char * casc_cflags2) {
368    if (dump_stage) {
369        cerr << "Compiling C/C++ code for scheduling...\n";
370    }
371    char compil_str[512];
372    const char * compiler = getenv("CXX");
373    const char * systemc_dir = getenv("SYSTEMCASS");
374    const char * default_compiler =
375#ifdef CPP_CALL
376        "g++";
377#else
378    "gcc";
379#endif
380
381    compiler = (compiler == NULL) ? default_compiler : compiler;
382    if (systemc_dir == NULL) {
383        systemc_dir = getenv("SYSTEMC");
384        if (systemc_dir == NULL) {
385            cerr << "Error : set SYSTEMCASS or SYSTEMC environnement variable to the SYSTEMCASS directory.\n";
386            exit(-1);
387        }
388    }
389
390    char target_name[128];
391    char source_name[128];
392    sprintf(target_name, "%s.lo", base_name);
393    sprintf(source_name, "%s.cc", base_name);
394
395    if (keep_generated_code) {
396        char lg_cde[256];
397        sprintf(lg_cde, "mkdir -p %s", generated_files_dir);
398        system(lg_cde);
399        sprintf(lg_cde, "cp %s/%s %s/", temporary_dir, source_name, generated_files_dir);
400        if (dump_stage) {
401            cerr << "$ " << lg_cde << "\n";
402        }
403        system(lg_cde);
404        sprintf(lg_cde, "(cd %s ; indent %s)", generated_files_dir, source_name);
405        if (dump_stage) {
406            cerr << "$ " << lg_cde << "\n";
407        }
408        system(lg_cde);
409    }
410    /* ******* */
411    /* COMPILE */
412    /* ******* */
413    const char * commandline_template =
414#if defined(CONFIG_OS_DARWIN)
415        "(cd %s ;"
416        " %s %s -DSCHEDULING_BY_CASC -I%s/include -fno-common -dynamic -o %s -c %s)"
417#elif defined(CONFIG_OS_LINUX)
418        "(cd %s ; libtool --mode=compile %s %s -DSCHEDULING_BY_CASC -I%s/include -shared -o %s -c %s)"
419#else
420        "(cd %s ;"
421        " %s %s -DSCHEDULING_BY_CASC -I%s/include -dynamiclib -o %s -c %s)"
422#endif
423        ;
424
425    string cflags = casc_cflags;
426    if (use_openmp) {
427        cflags += " -fopenmp";
428    }
429
430    sprintf(compil_str, commandline_template, temporary_dir, compiler, cflags.c_str(), systemc_dir, target_name, source_name);
431
432    if (dump_stage) {
433        cerr << "Executing command : " << compil_str << "\n";
434    }
435
436    if (system(compil_str)) {
437        perror("compil : system");
438        exit(-1);
439    }
440
441    /* **** */
442    /* LINK */
443    /* **** */
444    sprintf(target_name, "%s.la", base_name);
445
446#ifdef CONFIG_OS_LINUX
447    sprintf(source_name, "%s.lo", base_name);
448    sprintf(compil_str, "(cd %s ; pwd ; libtool --mode=link %s %s -module -shared -o %s %s -rpath /tmp)", /* -L. -L%s/lib-%s */
449            temporary_dir, compiler, casc_cflags, /*systemc_dir, target_arch, */
450            target_name, source_name);
451#else
452    sprintf(source_name, "%s.o", base_name);
453    sprintf(compil_str, "(cd %s ; pwd ; libtool -dynamic -o %s %s)", temporary_dir, target_name, source_name);
454#endif
455
456    if (dump_stage) {
457        cerr << "Executing command : " << compil_str << "\n";
458    }
459
460    if (system(compil_str)) {
461        perror("compil : system");
462        exit(-1);
463    }
464
465    system(compil_str);
466    if (dump_stage) {
467        cerr << "Compiling done.\n";
468    }
469}
470
471
472/* ********************************
473 * Function for static scheduling
474 */
475struct function_call {
476    fct * function;
477    void ** instance;
478    int func_number;
479};
480static function_call pf[3];
481
482
483void get_function_call(function_call & pf, method_process_list_t & func_list) {
484    pf.func_number = func_list.size();
485    pf.function = (fct *) malloc(sizeof(fct) * pf.func_number);
486    pf.instance = (void **) malloc(sizeof(void *) * pf.func_number);
487    method_process_list_t::iterator mm;
488    int i;
489    for (mm = func_list.begin(), i = 0; mm != func_list.end(); ++mm, ++i) {
490        const method_process_t * mp = *mm;
491        pf.function[i].pmf = (mp->func);
492        pf.instance[i] = (void *) (mp->module);
493    }
494}
495
496
497void get_function_call(function_call & pf, ProcessDependencyList & func_list) {
498    pf.func_number = func_list.size();
499    pf.function = (fct *) malloc(sizeof(fct) * pf.func_number);
500    pf.instance = (void **) malloc(sizeof(void *) * pf.func_number);
501    ProcessDependencyList::iterator it;
502    int i;
503    for (i = 0, it = func_list.begin(); it != func_list.end(); ++it, ++i) {
504        const method_process_t * mp = *it;
505        pf.function[i].pmf = (mp->func);
506        pf.instance[i] = (void *) (mp->module);
507    }
508}
509
510
511void gen_scheduling_code_for_static_func(method_process_list_t &
512        transition_func_list,
513        method_process_list_t &
514        moore_func_list,
515        ProcessDependencyList &
516        mealy_func_list) {
517    if (dump_stage) {
518        cerr << "Generating scheduling...\n";
519    }
520
521    get_function_call(pf[0], transition_func_list);
522    get_function_call(pf[1], moore_func_list);
523    get_function_call(pf[2], mealy_func_list);
524
525    if (dump_stage) {
526        cerr << "Generating scheduling done.\n";
527    }
528}
529
530
531void call_functions(function_call & fc) {
532    int n = fc.func_number;
533    int i;
534    for (i = 0; i < n; ++i) {
535#if 0
536        //defined(CONFIG_DEBUG)
537        sc_module *m = (sc_module *) (fc.instance[i]);
538        cerr << m->name() << endl;
539#endif
540        fc.function[i].pf(fc.instance[i]);
541    }
542}
543
544
545void call_functions_in_parallel(function_call & fc) {
546    int n = fc.func_number;
547    int i;
548#pragma omp parallel for
549    for (i = 0; i < n; ++i) {
550#if 0
551        //defined(CONFIG_DEBUG)
552        sc_module *m = (sc_module *) (fc.instance[i]);
553        cerr << m->name() << endl;
554        cerr << "thread #" << omp_get_thread_num() << endl;
555#endif
556        fc.function[i].pf(fc.instance[i]);
557    }
558}
559
560
561void static_mealy_generation() {
562    call_functions(pf[2]);
563}
564
565
566void static_simulate_1_cycle(void) {
567    call_functions(pf[0]); // transition
568    update();
569    call_functions_in_parallel(pf[1]); // moore generation
570    call_functions(pf[2]); // mealy generation
571}
572
573
574/* ***************************************
575 * Function for quasi static scheduling
576 */
577
578unsigned int nb_func[2];
579static method_process_t **func_list[2];
580#pragma omp threadprivate (nb_func, func_list)
581static strong_component_list_t quasistatic_list;
582
583unsigned long long busy_wait_f0, busy_wait_f1, busy_wait_up, busy_wait_ml;
584unsigned long long last_wait_f0, last_wait_f1, last_wait_up, last_wait_ml;
585#pragma omp threadprivate (busy_wait_f0, busy_wait_f1, busy_wait_up,busy_wait_ml)
586#pragma omp threadprivate (last_wait_f0, last_wait_f1, last_wait_up,last_wait_ml)
587
588static void Call(const method_process_t & m) {
589    sc_module * mod = m.module;
590    SC_ENTRY_FUNC func = m.func;
591    //  CASC_ENTRY_FUNC   func = reinterpret_cast<CASC_ENTRY_FUNC> (m.func);
592    // QM
593    //cerr << "Exec " << mod->name() << "->" << m.name << endl;
594    (mod->*func) ();
595}
596
597
598void quasistatic_mealy_generation() {
599    strong_component_list_t::iterator ss;
600    for (ss = quasistatic_list.begin(); ss != quasistatic_list.end(); ++ss) {
601        if ((*ss)->size() == 1) {
602            /* un seul element dans le strong component */
603            method_process_t * m = (method_process_t *) (*((*ss)->begin()));
604            Call(*m);
605            continue;
606        }
607        else {
608            /* plusieurs elements dans le strong component */
609            do {
610                unstable = 0;
611                component_list_t::reverse_iterator rev_mm;
612                for (rev_mm = (*ss)->rbegin(); rev_mm != (*ss)->rend(); ++rev_mm) {
613                    method_process_t * m = (method_process_t *) * rev_mm;
614                    Call(*m);
615                }
616            } while (unstable);
617        }
618    }
619}
620
621unsigned int expected_globaltime = 0;
622volatile unsigned int globaltime __attribute__ ((aligned (128))) = 0;
623#pragma omp shared (globaltime)
624#pragma omp threadprivate (expected_globaltime)
625
626unsigned int num_omp_threads;
627
628void quasistatic_simulate_1_cycle(void) {
629    int i;
630
631    for (i = 0; i < nb_func[0]; ++i) {
632        Call(*(func_list[0][i]));
633    }
634#define USE_BUSY_WAIT 1
635    update();
636#if USE_BUSY_WAIT
637    expected_globaltime += num_omp_threads;
638    if (__sync_add_and_fetch(&globaltime, 1) == expected_globaltime) {
639        last_wait_up++;
640    }
641    __asm volatile("mfence");
642    while (globaltime < expected_globaltime) {
643        busy_wait_up++;
644        __asm volatile("lfence");
645    }
646
647#else
648#pragma omp barrier
649#endif
650
651    for (i = 0; i < nb_func[1]; ++i) {
652        Call(*(func_list[1][i]));
653    }
654
655#if USE_BUSY_WAIT
656    expected_globaltime += num_omp_threads;
657    if (__sync_add_and_fetch(&globaltime, 1) == expected_globaltime) {
658        last_wait_f1++;
659    }
660    __asm volatile("mfence");
661    while (globaltime < expected_globaltime) {
662        busy_wait_f1++;
663        __asm volatile("lfence");
664    }
665#else
666#pragma omp barrier
667#endif
668    if (!quasistatic_list.empty()) {
669#pragma omp master
670        {
671            quasistatic_mealy_generation();
672        }
673#if USE_BUSY_WAIT
674        expected_globaltime += num_omp_threads;
675        if (__sync_add_and_fetch(&globaltime, 1) == expected_globaltime) {
676            last_wait_ml++;
677        }
678        __asm volatile("mfence");
679        while (globaltime < expected_globaltime) {
680            busy_wait_ml++;
681            __asm volatile("lfence");
682        }
683#else
684#pragma omp barrier
685#endif
686    }
687
688}
689
690
691void gen_scheduling_code_for_quasistatic_func(method_process_list_t &
692        transition_func_list,
693        method_process_list_t &
694        moore_func_list,
695        strong_component_list_t *
696        mealy_func_list) {
697    if (dump_stage) {
698        cerr << "Generating quasi static scheduling...\n";
699    }
700
701    nb_func[0] = transition_func_list.size();
702    nb_func[1] = moore_func_list.size();
703
704    func_list[0] = (method_process_t**) malloc(sizeof (method_process_t*) * nb_func[0]);
705    func_list[1] = (method_process_t**) malloc(sizeof (method_process_t*) * nb_func[1]);
706
707    unsigned int i;
708    for (i = 0; i < nb_func[0]; ++i) {
709        func_list[0][i] = (transition_func_list[i]);
710    }
711
712    for (i = 0; i < nb_func[1]; ++i) {
713        func_list[1][i] = (moore_func_list[i]);
714    }
715
716    if (mealy_func_list != NULL) {
717        quasistatic_list = *mealy_func_list;
718    }
719
720    if (dump_stage) {
721        cerr << "Generating quasi static scheduling done.\n";
722    }
723}
724} // end of sc_core namespace
725
726
727/*
728# Local Variables:
729# tab-width: 4;
730# c-basic-offset: 4;
731# c-file-offsets:((innamespace . 0)(inline-open . 0));
732# indent-tabs-mode: nil;
733# End:
734#
735# vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
736*/
Note: See TracBrowser for help on using the repository browser.