source: sources/src/schedulers.cc

Last change on this file was 65, checked in by bouyer, 5 years ago

Various performance improvements for the parallel systemcass: cache-aligned
data structures, write only when needed, disable some unneeded barriers.

Fix bug in the non-openmp case: a pointer was not initialized

various style updates

File size: 10.5 KB
Line 
1/*------------------------------------------------------------\
2|                                                             |
3| Tool    :                  systemcass                       |
4|                                                             |
5| File    :                 schedulers.cc                     |
6|                                                             |
7| Author  :                 Buchmann Richard                  |
8|                           Nicolas Pouillon                  |
9|                                                             |
10| Date    :                   23_03_2007                      |
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#include <cstdio>
38#include <cassert>
39#include <iostream>
40#include <algorithm> //std::sort
41
42#include "sc_module.h" // method_process_t
43#include "gen_code.h"  // gen_scheduling_code_for_dynamic_link & gen_scheduling_code_for_static_func
44#include "internal.h"  // dump_all_graph
45#include "graph_cass.h" // makegraph
46#include "process_dependency.h" // MakeProcessDependencyList
47#include "signal_dependency.h" // MakeSignalDependencyGraph
48#include "mouchard_scheduling.h" // MakeMouchardScheduling
49#include "graph_signals.h" // makegraph
50
51#ifdef _OPENMP
52    #include <omp.h>
53#endif
54
55#ifdef HAVE_CONFIG_H
56#include "config.h"
57#endif
58
59using namespace std;
60
61namespace sc_core {
62
63//
64// sort_functions splits and sorts instances_list into three functions lists :
65method_process_list_t *transition_func_list;
66method_process_list_t *moore_func_list;
67#ifdef _OPENMP
68#pragma omp threadprivate (transition_func_list, moore_func_list)
69#endif
70method_process_list_t combinational_func_list;
71
72/* ***************************** */
73/* Dumping functions (for debug) */
74/* ***************************** */
75
76template <typename T>
77ostream & operator << (ostream & o, const vector<T*> & v) {
78    typename vector<T *>::const_iterator i;
79    for (i = v.begin(); i != v.end(); ++i) {
80        o << **i << " ";
81    }
82    return o;
83}
84
85/* ************ */
86/*  functions   */
87/****************/
88
89static bool sort_by_module_ptr (const method_process_t * a1, const method_process_t * a2) {
90    assert(a1 != NULL);
91    assert(a2 != NULL);
92    return (a1->module < a2->module);
93}
94
95
96static bool sort_by_fct_ptr (const method_process_t * a1, const method_process_t * a2) {
97    assert(a1 != NULL);
98    assert(a2 != NULL);
99    union {
100        SC_ENTRY_FUNC func;
101        unsigned long addr_l;
102        unsigned long long addr_ll;
103    } addr1, addr2;
104
105    addr1.func = a1->func;
106    addr2.func = a2->func;
107   
108    if (a1->func == a2->func) {
109        return sort_by_module_ptr(a1,a2);
110    }
111
112    if (sizeof(SC_ENTRY_FUNC) == 4 ) {
113        return (addr1.addr_l < addr2.addr_l);
114    }
115    else {
116        return (addr1.addr_ll < addr2.addr_ll);
117    }
118}
119
120
121
122void sort_functions() {
123    method_process_list_t::const_iterator m;
124#ifdef _OPENMP
125#pragma omp parallel
126#pragma omp critical
127#endif
128    {
129        transition_func_list = new method_process_list_t;
130        moore_func_list = new method_process_list_t;
131        for (m = method_process_list.begin(); m != method_process_list.end(); ++m) {
132#ifdef _OPENMP
133            if ((*m)->omp_threadnum == omp_get_thread_num())
134#endif
135            {
136                if ((*m)->is_transition ())
137                    transition_func_list->push_back(*m);
138                else if ((*m)->is_genmoore ())
139                    moore_func_list->push_back(*m);
140            }
141        }
142#if 1
143        // Sort transition functions by method pointer (1) and by module pointer (2)
144        std::sort (transition_func_list->begin(), transition_func_list->end(), sort_by_fct_ptr);
145        // Sort generation functions by method pointer (1) and by module pointer (2)
146        std::sort (moore_func_list->begin(), moore_func_list->end(), sort_by_fct_ptr);
147#endif
148#if 0
149        std::sort (transition_func_list->begin(), transition_func_list->end(), only_sort_by_module_ptr);
150        std::sort (moore_func_list->begin(), moore_func_list->end(), only_sort_by_module_ptr);
151#endif
152  }
153
154  for (m = method_process_list.begin(); m != method_process_list.end(); ++m) {
155    if ((*m)->is_combinational()) combinational_func_list.push_back(*m);
156  }
157}
158
159/* ****************** */
160/* process dependency */
161/* ****************** */
162
163static SignalDependencyGraph * MakeAcyclicSignalDependencyGraph() {
164    if (dump_all_graph) {
165        const PortDependencyGraph & port_graph = get_port_dependency_graph ();
166        PortDependencyGraph2dot ("port_graph", port_graph);
167    }
168
169    SignalDependencyGraph * sig_graph = MakeSignalDependencyGraph();
170
171    if (dump_all_graph) {
172        SignalDependencyGraph2dot ("signal_graph",*sig_graph);
173    }
174
175    if (!Check(*sig_graph)) {
176        cerr << "The signal dependency graph is not valid.\n";
177        exit (29092004);
178    }
179
180    if (!Check(method_process_list, *sig_graph)) {
181        cerr << "Sensitivity list is not valid.\n";
182        exit (30092004);
183    }
184
185    // There is a cycle in the signal dependency graph ?
186    Graph * sig_knuth = makegraph(*sig_graph);
187    strong_component_list_t * s = strong_component(sig_knuth);
188
189    if (dump_all_graph) {
190        SignalDependencyOrder2txt("signal_order",*s);
191    }
192
193    if (has_cycle(*s)) {
194        cerr << "Error : There is a cycle in the signal dependency graph.\n";
195        exit (24092004);
196    }
197    delete s;
198    return sig_graph;
199}
200
201
202static ProcessDependencyList * MouchardScheduling() {
203    SignalDependencyGraph * sig_graph = MakeAcyclicSignalDependencyGraph();
204    assert(sig_graph != NULL);
205    // Create the process evaluation list
206    ProcessDependencyList * process_list = MakeMouchardScheduling(*sig_graph);
207    assert(process_list != NULL);
208
209    if (dump_all_graph) {
210        ProcessDependencyList2dot  ("process_order", *process_list);
211    }
212
213    return process_list;
214}
215
216
217static ProcessDependencyList * BuchmannScheduling() {
218    SignalDependencyGraph * sig_graph = MakeAcyclicSignalDependencyGraph();
219    // Create the process evaluation list
220    ProcessDependencyList * process_list = MakeProcessDependencyList(*sig_graph);
221
222    if (dump_all_graph) {
223        ProcessDependencyList2dot("process_order", *process_list);
224    }
225
226    return process_list;
227}
228
229string
230get_scheduling (int scheduling_method) 
231{
232  string base_name;
233  /* marque les fonctions comme fonction de mealy ou non */
234  if (dump_funclist_info)
235    cerr << "method process list : " << method_process_list << "\n";
236  sort_functions ();
237#ifdef _OPENMP
238#pragma omp parallel
239#pragma omp critical
240#endif
241    {
242        if (dump_funclist_info) {
243#ifdef _OPENMP
244            cerr << "Thread " << omp_get_thread_num() << "\n";
245#endif
246    cerr << "  Transition functions : " << *transition_func_list << "\n";
247    cerr << "  Moore generation functions : " << *moore_func_list << "\n";
248#ifdef _OPENMP
249#pragma omp master
250#endif
251    {
252      if (!combinational_func_list.empty()) {
253            cerr << "Mealy generation functions : " <<
254                combinational_func_list << "\n";
255      }
256    }
257  }
258
259  /* Schedule */ 
260  switch (scheduling_method) {
261  case BUCHMANN_SCHEDULING : {
262    // Generate the scheduled code, compile and link.
263    // Buchmann's thesis explains this scheduling method.
264    // Uses port dependancies like Dr. Mouchard.
265    ProcessDependencyList* process_list = BuchmannScheduling ();
266  if (dynamic_link_of_scheduling_code)
267    base_name = gen_scheduling_code_for_dynamic_link (*transition_func_list, *moore_func_list,*process_list);
268  else
269    gen_scheduling_code_for_static_func (*transition_func_list, *moore_func_list, *process_list);
270    break;
271  }
272  case MOUCHARD_SCHEDULING : {
273    // Generate the scheduled code, compile and link.
274    // Mouchard's thesis explains this scheduling method.
275    // Uses port dependancies like Dr. Mouchard.
276    // CAUTION : unlike FastSysC, this scheduling is totally static
277    // and does not use an event-driven scheduler.
278    ProcessDependencyList* process_list = MouchardScheduling ();
279  if (dynamic_link_of_scheduling_code)
280    base_name = gen_scheduling_code_for_dynamic_link(*transition_func_list, *moore_func_list,*process_list);
281  else
282    gen_scheduling_code_for_static_func (*transition_func_list, *moore_func_list, *process_list);
283    break;
284  }
285  case CASS_SCHEDULING : {
286    // Generate the scheduled code, compile and link
287    // Hommais's thesis explains this scheduling method (like CASS strategy)
288    // Doesn't use port dependancies
289    strong_component_list_t *strong_list = NULL;
290#ifdef _OPENMP
291#pragma omp master
292#endif
293    {
294    Graph *g = makegraph (&combinational_func_list);
295    if (dump_all_graph && g)
296      graph2dot("module_graph", *g);
297    strong_list = strong_component (g);
298    }
299  if (dynamic_link_of_scheduling_code)
300    base_name = gen_scheduling_code_for_dynamic_link(*transition_func_list, *moore_func_list,strong_list);
301  else
302    gen_scheduling_code_for_quasistatic_func (*transition_func_list, *moore_func_list, strong_list);
303#ifdef _OPENMP
304#pragma omp master
305#endif
306  {
307    delete strong_list;
308  }
309  break;
310  }
311  default :
312    cerr << "Error : Unable to schedule SystemC process."
313            "Please select a scheduling method.\n";
314    exit (35);
315  }
316  }
317  return base_name;
318}
319
320
321bool run_schedule_editor (const char * schedule) {
322    char buf[128];
323    const char * editor = getenv("EDITOR");
324    if (editor == NULL) {
325        editor = "vim";
326    }
327    sprintf (buf, "(cd '%s' ; %s '%s')", temporary_dir, editor, schedule);
328    if (dump_stage) {
329        cerr << "Executing : " << buf << endl;
330    }
331    return (system(buf) == 0);
332}
333
334
335} // end of sc_core namespace
336
337/*
338# Local Variables:
339# tab-width: 4;
340# c-basic-offset: 4;
341# c-file-offsets:((innamespace . 0)(inline-open . 0));
342# indent-tabs-mode: nil;
343# End:
344#
345# vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
346*/
347
Note: See TracBrowser for help on using the repository browser.