Otawa  0.10
GraphBBTime.h
Go to the documentation of this file.
1 /*
2  * GraphBBTime interface
3  *
4  * This file is part of OTAWA
5  * Copyright (c) 2005-12 IRIT UPS.
6  *
7  * OTAWA is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * OTAWA is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with OTAWA; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  */
22 #ifndef OTAWA_GRAPH_BBTIME_H
23 #define OTAWA_GRAPH_BBTIME_H
24 
25 #include <otawa/ipet.h>
26 #include <otawa/prop/Identifier.h>
27 #include <otawa/cfg.h>
29 //#include <otawa/cache/categorisation/CATBuilder.h>
30 #include <otawa/hard/Memory.h>
32 #include <elm/io/OutFileStream.h>
33 #include <otawa/ipet.h>
35 
36 
37 namespace otawa {
38  extern Identifier<String> GRAPHS_OUTPUT_DIRECTORY;
39  extern Identifier<int> TIME;
40 
41  class LBlockManager {
42  public:
43 
44  LBlockManager(void): bb(0), lbs(0), i(0) { }
45 
47 
48  // perform initialization for a new bb
49  if(ibb != bb) {
50  bb = ibb;
51  lbs = BB_LBLOCKS(bb);
52  i = 0;
53  }
54 
55  // is it a l-block bound?
56  if(i < lbs->count() && lbs->get(i)->address() == inst->address()) {
57  category_t cat = CATEGORY(lbs->get(i));
58  if(cat == FIRST_MISS)
59  hd = cache::CATEGORY_HEADER(lbs->get(i));
60  i++;
61  return cat;
62  }
63  else
65  }
66 
67  inline BasicBlock *header(void) const { return hd; }
68 
69  private:
73  int i;
74  };
75 
76 
77  using namespace elm::genstruct;
78 
79  // -- class PathContext --------------------------------------------------------------------------------
80  class PathContext{
81  private:
84  int _num_bbs;
87  public:
89  _bb_list.addFirst(bb);
90  _num_insts = bb->countInstructions();
91  _num_bbs = 1;
92  _bb = bb;
93  _edge = NULL;
94  }
95  PathContext(const PathContext& ctxt){
96  for (elm::genstruct::SLList<BasicBlock *>::Iterator block(ctxt._bb_list) ; block ; block++)
97  _bb_list.addLast(block);
98  _num_insts = ctxt._num_insts;
99  _num_bbs = ctxt._num_bbs;
100  _bb = ctxt._bb;
101  _edge = ctxt._edge;
102  }
104  _bb_list.clear();
105  }
106  void addBlock(BasicBlock * new_bb, Edge * edge){
107  _bb_list.addFirst(new_bb);
108  _num_insts += new_bb->countInstructions();
109  _num_bbs += 1;
110  if (_num_bbs == 1)
111  _bb = new_bb;
112  if (_num_bbs == 2)
113  _edge = edge;
114  }
115  inline int numInsts()
116  { return _num_insts;}
117  inline int numBlocks()
118  { return _num_bbs;}
120  { return _bb_list.last();}
122  { return _bb;}
123  inline Edge * edge ()
124  { return _edge;}
125  void dump(io::Output& output) {
127  output << "b" << bb->number() << "-";
128  }
129  }
130 
131  class BasicBlockIterator: public elm::genstruct::SLList<BasicBlock *>::Iterator {
132  public:
133  inline BasicBlockIterator(const PathContext& ctxt)
134  : elm::genstruct::SLList<BasicBlock *>::Iterator(ctxt._bb_list) {}
135  };
136 
137  };
138 
139 
140  // -- class GraphBBTime ----------------------------------------------------------------------------------
141 
142  template <class G>
143  class GraphBBTime: public BBProcessor {
144  private:
151 
152  protected:
159 
160  virtual int cacheMissPenalty(Address addr) const;
161  virtual int memoryLatency(Address addr) const;
162  virtual void buildNCTimingContextListForICache(elm::genstruct::SLList<TimingContext *> *list, ParExeSequence *seq);
163  virtual void buildFMTimingContextListForICache(elm::genstruct::SLList<TimingContext *> *list, ParExeSequence *seq);
164  virtual void computeDefaultTimingContextForICache(TimingContext *dtctxt, ParExeSequence *seq);
165  virtual void BuildVectorOfHwResources();
166  virtual void configureMem(WorkSpace *ws) {
167  icache = hard::CACHE_CONFIGURATION(ws)->instCache();
168  _do_consider_icache = icache;
169  mem = hard::MEMORY(ws);
170  }
171 
172  public:
173  //GraphBBTime(const PropList& props = PropList::EMPTY);
175  GraphBBTime(AbstractRegistration& _reg = reg);
176  virtual void configure(const PropList& props);
177 
178  void processWorkSpace(WorkSpace *ws);
179  void processBB(WorkSpace *ws, CFG *cfg, BasicBlock *bb);
180  elm::genstruct::SLList<PathContext *> * buildListOfPathContexts(BasicBlock *bb, int depth = 1);
181  void FillSequence(PathContext *ctxt,
183  int depth);
184  ParExeSequence * buildSequence(PathContext *ctxt);
185  void analyzePathContext(PathContext *ctxt, int context_index);
186  int analyzeTimingContext(G* graph, TimingContext *NC_ctxt, TimingContext *FM_ctxt);
187  void outputGraph(G* graph, int bb_number, int context_number, int case_number, const string& info = "");
188 
189  };
190  // -- GraphBBTime ------------------------------------------------------------------------------------------
191 
192  template <class G>
194  const hard::Bank *bank = mem->get(addr);
195  ASSERTP(bank, "no bank for memory access at " << addr);
196  return bank->latency();
197  }
198 
199  template <class G>
201  const hard::Bank *bank = mem->get(addr);
202  if(!bank)
203  throw ProcessorException(*this, _ << "no bank for memory access at " << addr);
204  return bank->latency();
205  }
206 
207  /*template <class G>
208  GraphBBTime<G>::GraphBBTime(const PropList& props)
209  : BBProcessor() {
210  _graphs_dir_name = GRAPHS_OUTPUT_DIRECTORY(props);
211  if (!_graphs_dir_name.isEmpty())
212  _do_output_graphs = true;
213  else
214  _do_output_graphs = false;
215  //_icache_miss_penalty = -1;
216  if (CACHE_CONFIG_PATH(props)){
217  _do_consider_icache = true;
218  }
219  else
220  _do_consider_icache = false;
221 
222  _props = props;
223  provide(ipet::BB_TIME_FEATURE);
224  // provide(ICACHE_ACCURATE_PENALTIES_FEATURE);
225  }*/
226 
227 template <class G>
229 : BBProcessor(_reg) {
230  /*require(hard::PROCESSOR_FEATURE);
231  require(hard::MEMORY_FEATURE);
232  provide(ipet::BB_TIME_FEATURE);*/
233 }
234 
235 template <class G>
237  "", Version(1, 0, 0),
242  p::end
243  );
244 
245 
246 template <class G>
248  BBProcessor::configure(props);
249  _graphs_dir_name = GRAPHS_OUTPUT_DIRECTORY(props);
250  if(!_graphs_dir_name.isEmpty())
251  _do_output_graphs = true;
252  else
253  _do_output_graphs = false;
254  //_icache_miss_penalty = -1;
255  if(CACHE_CONFIG_PATH(props)){
256  _do_consider_icache = true;
257  }
258  else
259  _do_consider_icache = false;
260  _props = props;
261 }
262 
263 
264 
265  // -- processWorkSpace ------------------------------------------------------------------------------------------
266 
267  template <class G>
269 
270  _ws = ws;
271  const hard::Processor *proc = hard::PROCESSOR(_ws);
272  if(proc == &hard::Processor::null)
273  throw ProcessorException(*this, "no processor to work with");
274 // else {
275  _microprocessor = new ParExeProc(proc);
276  BuildVectorOfHwResources(); // ===== TO BE ENABLED
277  configureMem(_ws);
278 // }
279 
280  // Perform the actual process
282  }
283 
284  // -- Build vector of pipeline-related resources -----------------------------------------------------------
285 
286  template <class G>
288 
289  int resource_index = 0;
290  bool is_ooo_proc = false;
291 
292  // build the start resource
293  StartResource * new_resource = new StartResource((elm::String) "start", resource_index++);
294  _hw_resources.add(new_resource);
295 
296  // build resource for stages and FUs
297  for (ParExePipeline::StageIterator stage(_microprocessor->pipeline()) ; stage ; stage++) {
298  if (stage->category() != ParExeStage::EXECUTE) {
299  for (int i=0 ; i<stage->width() ; i++) {
300  StringBuffer buffer;
301  buffer << stage->name() << "[" << i << "]";
302  StageResource * new_resource = new StageResource(buffer.toString(), stage, i, resource_index++);
303  _hw_resources.add(new_resource);
304  }
305  }
306  else { // EXECUTE stage
307  if (stage->orderPolicy() == ParExeStage::IN_ORDER) {
308  for (int i=0 ; i<stage->numFus() ; i++) {
309  ParExePipeline * fu = stage->fu(i);
310  ParExeStage *fu_stage = fu->firstStage();
311  for (int j=0 ; j<fu_stage->width() ; j++) {
312  StringBuffer buffer;
313  buffer << fu_stage->name() << "[" << j << "]";
314  StageResource * new_resource = new StageResource(buffer.toString(), fu_stage, j, resource_index++);
315  _hw_resources.add(new_resource);
316  }
317  }
318  }
319  else
320  is_ooo_proc = true;
321  }
322  }
323 
324  // build resources for queues
325  for (ParExeProc::QueueIterator queue(_microprocessor) ; queue ; queue++) {
326  int num = queue->size();
327  for (int i=0 ; i<num ; i++) {
328  StringBuffer buffer;
329  buffer << queue->name() << "[" << i << "]";
330  StageResource * upper_bound;
331  for (elm::genstruct::Vector<Resource *>::Iterator resource(_hw_resources) ; resource ; resource++) {
332  if (resource->type() == Resource::STAGE) {
333  if (((StageResource *)(*resource))->stage() == queue->emptyingStage()) {
334  if (i < queue->size() - ((StageResource *)(*resource))->stage()->width() - 1) {
335  if (((StageResource *)(*resource))->slot() == ((StageResource *)(*resource))->stage()->width()-1) {
336  upper_bound = (StageResource *) (*resource);
337  }
338  }
339  else {
340  if (((StageResource *)(*resource))->slot() == i - queue->size() + ((StageResource *)(*resource))->stage()->width()) {
341  upper_bound = (StageResource *) (*resource);
342  }
343  }
344  }
345  }
346  }
347  ASSERT(upper_bound);
348  // build the queue resource
349  QueueResource * new_resource = new QueueResource(buffer.toString(), queue, i, resource_index++, upper_bound, _microprocessor->pipeline()->numStages());
350  _hw_resources.add(new_resource);
351  }
352  }
353 
354  // build resources for registers
355 // const otawa::hard::Platform::banks_t & reg_banks = ws->platform()->banks() ;
356 // elm::cout << reg_banks.count() << " banks to consider \n";
357 // for (int b=0 ; b<reg_banks.count() ; b++) {
358 // otawa::hard::RegBank * bank = (otawa::hard::RegBank *) reg_banks.get(b);
359 // elm::cout << reg_banks.count() << " bank" << b << " has " << bank->count() << " registers\n";
360 // for (int r=0 ; r<bank->count() ; r++)
361 // {
362 // StringBuffer buffer;
363 // buffer << bank->name() << r;
364 // RegResource * new_resource = new RegResource(buffer.toString(), bank, r, resource_index++);
365 // _resources.add(new_resource);
366 // }
367 // }
368 }
369 
370  // -- FillSequence ------------------------------------------------------------------------------------------
371 
372  template <class G>
375  int depth){
376 
377  BasicBlock *bb = ctxt->lastBlock();
378  int last_stage_cap = _microprocessor->lastStage()->width();
379  int num_preds = 0;
380  for(BasicBlock::InIterator edge(bb); edge; edge++) {
381  BasicBlock *pred = edge->source();
382  if (!pred->isEntry() && !pred->isExit()) {
383  num_preds++;
384  PathContext *new_ctxt = new PathContext(*ctxt);
385  new_ctxt->addBlock(pred, edge);
386  if ( (new_ctxt->numInsts() >= last_stage_cap)
387  &&
388  (new_ctxt->numBlocks() > depth) )
389  context_list->addLast(new_ctxt);
390  else
391  FillSequence(new_ctxt, context_list, depth);
392  }
393  }
394  if (num_preds == 0){
395  context_list->addLast(ctxt);
396  }
397  else
398  delete ctxt;
399  }
400 
401 
402  // -- buildListOfPathContexts ---------------------------------------------------------------------------------------
403 
404  template <class G>
406  ASSERT(depth > 0);
408  PathContext * ctxt = new PathContext(bb);
409 
410  FillSequence(ctxt, context_list, depth);
411 
412  return context_list;
413  }
414 
415  // -- buildSequence ------------------------------------------------------------------------------------------
416 
417  template <class G>
419  ParExeSequence * seq = new ParExeSequence();
420  code_part_t part = PROLOGUE;
421  int index = 0;
422  for (PathContext::BasicBlockIterator block(*ctxt) ; block ; block++){
423  if (block == ctxt->mainBlock())
424  part = BLOCK;
425  for(BasicBlock::InstIterator inst(block); inst; inst++) {
426  ParExeInst * par_exe_inst = new ParExeInst(inst, block, part, index++);
427  seq->addLast(par_exe_inst);
428  }
429  }
430  return seq;
431  }
432 
433  // -- outputGraph ------------------------------------------------------------------------------------------
434 
435  template <class G>
436  void GraphBBTime<G>::outputGraph(G* graph, int bb_number, int context_index, int case_index, const string& info){
437  elm::StringBuffer buffer;
438  buffer << _graphs_dir_name << "/";
439  buffer << "b" << bb_number << "-ctxt" << context_index << "-case" << case_index << ".dot";
440  elm::io::OutFileStream dotStream(buffer.toString());
441  elm::io::Output dotFile(dotStream);
442  graph->dump(dotFile, info);
443  }
444 
445 
446  // -- buildNCTimingContextListForICache ---------------------------------------------------------------------------
447 
448  template <class G>
450 
452 
453  // process NOT_CLASSIFIED lblocks
454  LBlockManager lbm;
455  for (ParExeSequence::InstIterator inst(seq) ; inst ; inst++) {
456  category_t cat = lbm.next(inst->basicBlock(), inst->inst());
457  if (cat != otawa::INVALID_CATEGORY){
458  if (cat == cache::NOT_CLASSIFIED){
459  if (list->isEmpty()){
460  TimingContext *tctxt = new TimingContext();
461  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
462  tctxt->addNodeLatency(nl);
463  list->addLast(tctxt);
464  }
465  else {
466  for (elm::genstruct::SLList<TimingContext *>::Iterator tctxt(*list) ; tctxt ; tctxt++){
467  TimingContext *new_tctxt = new TimingContext(tctxt.item());
468  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
469  new_tctxt->addNodeLatency(nl);
470  to_add->addLast(new_tctxt);
471  }
472  for (elm::genstruct::SLList<TimingContext *>::Iterator tctxt(*to_add) ; tctxt ; tctxt++){
473  list->addLast(tctxt.item());
474  }
475  to_add->clear();
476  TimingContext *new_tctxt = new TimingContext();
477  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
478  new_tctxt->addNodeLatency(nl);
479  list->addLast(new_tctxt);
480  }
481  }
482  }
483  }
484  delete to_add;
485  }
486 
487  // -- buildFMTimingContextListForICache ---------------------------------------------------------------------------
488 
489  template <class G>
491 
492  BasicBlock *header0 = NULL;
493  BasicBlock *header1 = NULL;
494  int num_headers = 0;
495 
496  // process FIRST_MISS lblocks
497 
498  // find FIRST_MISS headers
499  LBlockManager lbm;
500  for (ParExeSequence::InstIterator inst(seq) ; inst ; inst++) {
501  category_t cat = lbm.next(inst->basicBlock(), inst->inst());
502  if (cat != otawa::INVALID_CATEGORY){
503  if (cat == cache::FIRST_MISS){
504  BasicBlock *header = lbm.header();
505  // elm::cout << "found header b" << header->number() << "\n";
506  if (header0 == NULL){
507  header0 = header;
508  // elm::cout << "\tsaved in header0\n";
509  num_headers++;
510  }
511  else {
512  if (header0 != header){
513  if (header1 == NULL){
514  if (Dominance::dominates(header, header0)){
515  header1 = header0;
516  header0 = header;
517  // elm::cout << "\tsaved in header0 (header1 takes header0)\n";
518  }
519  else {
520  header1 = header;
521  // elm::cout << "\tsaved in header1\n";
522  }
523  num_headers++;
524  }
525  else {
526  if (header1 != header) {
527  // third header: is not expected to be found - could be implemented by ignoring the first headers in the sequence
528  ASSERTP(0, "this sequence has more than 2 headers for cache categories: this is not supported so far\n");
529  }
530  // else
531  // elm::cout << "\talready found in header1\n";
532  }
533  } // header0 != header
534  // else {
535  // elm::cout << "\talready found in header0\n";
536  // }
537  }
538  }
539  }
540  }
541  // create timing contexts
542  if (num_headers){
543  if (num_headers == 1){
544  TimingContext *tctxt_first = new TimingContext(header0);
545  tctxt_first->setType(CachePenalty::MISS);
546  list->addLast(tctxt_first);
547 
548  LBlockManager lbm;
549  for (ParExeSequence::InstIterator inst(seq) ; inst ; inst++) {
550  cache::category_t cat = lbm.next(inst->basicBlock(), inst->inst());
551  if (cat != cache::INVALID_CATEGORY){
552  if (cat == cache::FIRST_MISS){ // must be with header0
553  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
554  tctxt_first->addNodeLatency(nl);
555  }
556  }
557  }
558  /* elm::cout << "One header: context is: \n"; */
559  /* for (TimingContext::NodeLatencyIterator nl(*tctxt_first) ; nl ; nl++){ */
560  /* elm::cout << "\t\t\t" << (nl.item())->node()->name() << " : lat=" << (nl.item())->latency() << "\n"; */
561  /* } */
562  }
563  else { // num_headers == 2
564  TimingContext *tctxt_first_first = new TimingContext(header0, header1);
565  tctxt_first_first->setType(CachePenalty::MISS_MISS);
566  list->addLast(tctxt_first_first);
567  TimingContext *tctxt_others_first = new TimingContext(header0, header1);
568  tctxt_others_first->setType(CachePenalty::HIT_MISS);
569  list->addLast(tctxt_others_first);
570  TimingContext *tctxt_first_others = new TimingContext(header0, header1);
571  tctxt_first_others->setType(CachePenalty::x_HIT);
572  list->addLast(tctxt_first_others);
573  LBlockManager lbm;
574  for (ParExeSequence::InstIterator inst(seq) ; inst ; inst++) {
575  cache::category_t cat = lbm.next(inst->basicBlock(), inst->inst());
576  if (cat != cache::INVALID_CATEGORY){
577  if (cat == cache::FIRST_MISS){
578  BasicBlock *header = lbm.header();
579  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
580  tctxt_first_first->addNodeLatency(nl);
581  nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
582  if (header == header0){
583  tctxt_first_others->addNodeLatency(nl);
584  }
585  else {// must be header==header1
586  tctxt_others_first->addNodeLatency(nl);
587  }
588  }
589  }
590  }
591  }
592  }
593  }
594 
595  // -- computeDefaultTimingContextForICache ---------------------------------------------------------------------------
596 
597  template <class G>
599  LBlockManager lbm;
600  for (ParExeSequence::InstIterator inst(seq) ; inst ; inst++) {
601  cache::category_t cat = lbm.next(inst->basicBlock(), inst->inst());
602  if (cat != cache::INVALID_CATEGORY){
603  if (cat == cache::ALWAYS_MISS) {
604  NodeLatency * nl = new NodeLatency(inst->fetchNode(), cacheMissPenalty(inst->inst()->address()));
605  dtctxt->addNodeLatency(nl);
606  }
607  }
608  }
609 
610  }
611 
612  // -- analyzeTimingContext ------------------------------------------------------------------------------------------
613 
614  template <class G>
616  graph->restoreDefaultLatencies();
617  if (NC_ctxt)
618  graph->setLatencies(NC_ctxt);
619  if (FM_ctxt)
620  graph->setLatencies(FM_ctxt);
621  int cost = graph->analyze();
622  return cost;
623  }
624 
625  // -- analyzePathContext ------------------------------------------------------------------------------------------
626 
627  template <class G>
628  void GraphBBTime<G>::analyzePathContext(PathContext*ctxt, int context_index){
629 
630  int case_index = 0;
631  BasicBlock * bb = ctxt->mainBlock();
632  Edge *edge = ctxt->edge();
633 
634 
635  ParExeSequence *sequence = buildSequence(ctxt);
636  G *execution_graph = new G(_ws,_microprocessor, &_hw_resources, sequence, _props);
637  execution_graph->build();
638 
639  // no cache
640  if(!_do_consider_icache)
641  for(typename G::InstIterator inst(execution_graph); inst; inst++)
642  inst->fetchNode()->setLatency(memoryLatency(inst->inst()->address()));
643 
644  // compute reference cost
645  int reference_cost = execution_graph->analyze();
646  if(isVerbose())
647  log << "\t\treference cost = " << reference_cost << "\n\n";
648  if (_do_output_graphs){
649  outputGraph(execution_graph, bb->number(), context_index, case_index++,
650  _ << "reference cost = " << reference_cost);
651  }
652 
653  // case of a cache
654  if (_do_consider_icache){
655 
656  // verbosity
657  if(isVerbose()) {
658  LBlockManager lbm;
659  for (ParExeSequence::InstIterator inst(sequence) ; inst ; inst++) {
660  cache::category_t cat = lbm.next(inst->basicBlock(), inst->inst());
661  if (cat != cache::INVALID_CATEGORY){
662  log << "\t\t\tcategory of I" << inst->index() << " is ";
663  switch(cat){
664  case cache::ALWAYS_HIT:
665  log << "ALWAYS_HIT\n";
666  break;
667  case cache::ALWAYS_MISS:
668  log << "ALWAYS_MISS\n";
669  break;
670  case cache::FIRST_MISS:
671  log << "FIRST_MISS (with header b" << lbm.header()->number() << ")\n";
672  break;
674  log << "NOT_CLASSIFIED\n";
675  break;
676  default:
677  log << "unknown !!!\n";
678  break;
679  }
680  }
681  }
682  }
683 
684  // set constant latencies (ALWAYS_MISS in the cache)
685  TimingContext default_timing_context;
686  computeDefaultTimingContextForICache(&default_timing_context, sequence);
687  int default_icache_cost = reference_cost;
688  if (!default_timing_context.isEmpty()){
689  if(isVerbose()) {
690  log << "\t\t\t\tdefault timing context: misses for";
691  for (TimingContext::NodeLatencyIterator nl(default_timing_context) ; nl ; nl++){
692  log << "I" << nl->node()->inst()->index() << ", ";
693  }
694  log << " - ";
695  }
696  execution_graph->setDefaultLatencies(&default_timing_context);
697  default_icache_cost = execution_graph->analyze();
698  if (_do_output_graphs) {
700  buf << "cost with AM = " << default_icache_cost << "\\lAM (";
701  for (TimingContext::NodeLatencyIterator nl(default_timing_context) ; nl ; nl++)
702  buf << "I" << nl->node()->inst()->index() << ", ";
703  buf << ")";
704  outputGraph(execution_graph, bb->number(), context_index, case_index++, buf.toString());
705  }
706  if(isVerbose())
707  log << "cost = " << default_icache_cost << " (only accounting for fixed latencies)\n\n";
708  if (default_icache_cost > reference_cost)
709  reference_cost = default_icache_cost;
710  }
711 
712  // consider variable latencies (FIRST_MISS, NOT_CLASSIFIED)
713  elm::genstruct::SLList<TimingContext *> NC_timing_context_list;
714  elm::genstruct::SLList<TimingContext *> FM_timing_context_list;
715  buildNCTimingContextListForICache(&NC_timing_context_list, sequence);
716  buildFMTimingContextListForICache(&FM_timing_context_list, sequence);
717 
718  int index = 0;
719  CachePenalty *cache_penalty = new CachePenalty();
720 
721  bool first = true;
722  if (!FM_timing_context_list.isEmpty()){
723  for (elm::genstruct::SLList<TimingContext *>::Iterator FM_tctxt(FM_timing_context_list) ; FM_tctxt ; FM_tctxt++){
724  if (first) {
725  cache_penalty->setHeader(0, FM_tctxt->header(0));
726  cache_penalty->setHeader(1, FM_tctxt->header(1));
727  first = false;
728  }
729  if (!NC_timing_context_list.isEmpty()){
730  for (elm::genstruct::SLList<TimingContext *>::Iterator NC_tctxt(NC_timing_context_list) ; NC_tctxt ; NC_tctxt++){
731  int NC_cost = analyzeTimingContext(execution_graph, NC_tctxt.item(), NULL);
732  if (NC_cost > reference_cost)
733  reference_cost = NC_cost;
734  int cost = analyzeTimingContext(execution_graph, NC_tctxt.item(), FM_tctxt.item());
735  if(isVerbose()) {
736  log << "\n\t\tcontext " << index << ": ";
737  for (TimingContext::NodeLatencyIterator nl(*(NC_tctxt.item())) ; nl ; nl++){
738  log << "I" << (nl.item())->node()->inst()->index() << ",";
739  }
740  for (TimingContext::NodeLatencyIterator nl(*(FM_tctxt.item())) ; nl ; nl++){
741  log << "I" << (nl.item())->node()->inst()->index() << ",";
742  }
743  log << " - ";
744  log << "cost=" << cost;
745  log << " - NC_cost=" << NC_cost << "\n";
746  }
747 
748  int penalty = cost - reference_cost;
749  // default_icache_cost is when all NCs hit
750  if ((FM_tctxt->type() == CachePenalty::x_HIT) && (penalty < 0))
751  penalty = 0; // penalty = max [ hit-hit, miss-hit ]
752  if (penalty > cache_penalty->penalty(FM_tctxt->type()))
753  cache_penalty->setPenalty(FM_tctxt->type(), penalty);
754  //cache_penalty->dump(elm::cout);
755  //elm::cout << "\n";
756  //elm::cout << " (penalty = " << penalty << " - p[" << FM_tctxt->type() << "] = " << cache_penalty->penalty(FM_tctxt->type()) << ")\n";
757  if (_do_output_graphs) {
759  buf << "FM-NC cost = " << cost << "\\lfirst(";
760  for (TimingContext::NodeLatencyIterator nl(*(FM_tctxt.item())) ; nl ; nl++)
761  buf << "I" << (nl.item())->node()->inst()->index() << ",";
762  buf << "),\\lNC(";
763  for (TimingContext::NodeLatencyIterator nl(*(NC_tctxt.item())) ; nl ; nl++)
764  buf << "I" << (nl.item())->node()->inst()->index() << ",";
765  buf << ")";
766  outputGraph(execution_graph, bb->number(), context_index, case_index++, buf.toString());
767  }
768  }
769  }
770  else { // no NC context
771  int cost = analyzeTimingContext(execution_graph, NULL, FM_tctxt.item());
772  if(isVerbose()) {
773  log << "\t\tcontext " << index << ": ";
774  for (TimingContext::NodeLatencyIterator nl(*(FM_tctxt.item())) ; nl ; nl++){
775  log << "I" << (nl.item())->node()->inst()->index() << ",";
776  }
777  log << " - ";
778  log << "cost=" << cost << "\n";
779  }
780  int penalty = cost - reference_cost;
781  if ((FM_tctxt->type() == CachePenalty::x_HIT) && (penalty < 0))
782  penalty = 0; // penalty = max [ hit-hit, miss-hit ]
783  if (penalty > cache_penalty->penalty(FM_tctxt->type()))
784  cache_penalty->setPenalty(FM_tctxt->type(), penalty);
785  /* cache_penalty->dump(elm::cout); */
786 /* elm::cout << "\n"; */
787 /* elm::cout << " (penalty = " << penalty << " - p[" << FM_tctxt->type() << "] = " << cache_penalty->penalty(FM_tctxt->type()) << ")\n"; */
788  if (_do_output_graphs){
790  buf << "NC cost = " << cost << "\\lNC (";
791  for (TimingContext::NodeLatencyIterator nl(*(FM_tctxt.item())) ; nl ; nl++)
792  buf << "I" << (nl.item())->node()->inst()->index() << ",";
793  buf << ")";
794  outputGraph(execution_graph, bb->number(), context_index, case_index++, buf.toString());
795  }
796  }
797  }
798 
799  }
800  else { // no FM context
801  for (elm::genstruct::SLList<TimingContext *>::Iterator NC_tctxt(NC_timing_context_list) ; NC_tctxt ; NC_tctxt++){
802  int NC_cost = analyzeTimingContext(execution_graph, NC_tctxt.item(), NULL);
803  if(isVerbose()) {
804  log << "\t\tcontext " << index << ": ";
805  for (TimingContext::NodeLatencyIterator nl(*(NC_tctxt.item())) ; nl ; nl++){
806  log << "I" << (nl.item())->node()->inst()->index() << ",";
807  }
808  log << " - ";
809  log << "cost=" << NC_cost << "\n";
810  }
811  if (NC_cost > reference_cost)
812  reference_cost = NC_cost;
813  if (_do_output_graphs){
815  buf << "NC cost = " << NC_cost << "\\l NC (";
816  for (TimingContext::NodeLatencyIterator nl(*(NC_tctxt.item())) ; nl ; nl++)
817  buf << "I" << (nl.item())->node()->inst()->index() << ",";
818  buf << ")";
819  outputGraph(execution_graph, bb->number(), context_index, case_index++, buf.toString());
820  }
821  }
822  }
823 
824  // set the cache penalty
825  if (cache_penalty->header(0)){
826  ICACHE_PENALTY(bb) = cache_penalty;
827  if (edge)
828  ICACHE_PENALTY(edge) = cache_penalty;
829  if(isVerbose()) {
830  log << "\t\tcache penalty: ";
831  cache_penalty->dump(log);
832  log << "\n";
833  }
834  }
835 
836  }
837 
838  // record the times
839  if(isVerbose())
840  log << "\t\tReference cost: " << reference_cost << "\n";
841  if (otawa::ipet::TIME(bb) < reference_cost)
842  otawa::ipet::TIME(bb) = reference_cost;
843  if (edge){
844  if (otawa::ipet::TIME(edge) < reference_cost){
845  otawa::ipet::TIME(edge) = reference_cost;
846  }
847  }
848 
849  // cleanup
850  delete execution_graph;
851  }
852 
853 
854  // -- processBB ------------------------------------------------------------------------------------------
855 
856  template <class G>
858 
859  // ignore empty basic blocks
860  if (bb->countInstructions() == 0)
861  return;
862 
863  if(isVerbose()) {
864  log << "\n\t\t================================================================\n";
865  log << "\t\tProcessing block b" << bb->number() << " (starts at " << bb->address() << " - " << bb->countInstructions() << " instructions)\n";
866  }
867 
868  int context_index = 0;
869 
870  elm::genstruct::SLList<PathContext *> *path_context_list = buildListOfPathContexts(bb);
871 
872  for (elm::genstruct::SLList<PathContext *>::Iterator ctxt(*path_context_list) ; ctxt ; ctxt++){
873  if(isVerbose()) {
874  log << "\n\t\t----- Considering context: ";
875  ctxt->dump(log);
876  log << "\n";
877  }
878  analyzePathContext(ctxt, context_index);
879  context_index ++;
880  }
881  }
882 
883 
884 } //otawa
885 
886 #endif // OTAWA_GRAPH_BBTIME_H
const hard::Cache * icache
Definition: GraphBBTime.h:156
int _num_insts
Definition: GraphBBTime.h:83
elm::genstruct::SLList< PathContext * > * buildListOfPathContexts(BasicBlock *bb, int depth=1)
Definition: GraphBBTime.h:405
Definition: categories.h:39
struct otawa::sem::inst inst
Identifier< const Processor * > PROCESSOR
Current memory.
int _prologue_depth
Definition: GraphBBTime.h:147
This processor is dedicated to the basic block process thru proccessBB() method.
Definition: BBProcessor.h:72
Iterator for the instruction queues.
Definition: ParExeProc.h:227
Representation of a pipeline stage to be used to build a ParExeGraph.
Definition: ParExeProc.h:86
Definition: ParExeProc.h:88
dtd::Element edge(dtd::make("edge", _EDGE).attr(source).attr(target).attr(called))
static const Processor null
Definition: Processor.h:151
elm::genstruct::SLList< BasicBlock * > _bb_list
Definition: GraphBBTime.h:82
Identifier< const Memory * > MEMORY
Current memory.
category_t next(BasicBlock *ibb, Inst *inst)
Definition: GraphBBTime.h:46
virtual void buildNCTimingContextListForICache(elm::genstruct::SLList< TimingContext * > *list, ParExeSequence *seq)
Definition: GraphBBTime.h:449
int analyzeTimingContext(G *graph, TimingContext *NC_ctxt, TimingContext *FM_ctxt)
Definition: GraphBBTime.h:615
void FillSequence(PathContext *ctxt, elm::genstruct::SLList< PathContext * > *context_list, int depth)
Definition: GraphBBTime.h:373
Definition: categories.h:38
virtual void configure(const PropList &props)
Configure the current processor.
Definition: GraphBBTime.h:247
PathContext(const PathContext &ctxt)
Definition: GraphBBTime.h:95
BasicBlock * mainBlock()
Definition: GraphBBTime.h:121
GraphBBTime(AbstractRegistration &_reg=reg)
Definition: GraphBBTime.h:228
BasicBlock * header(void) const
Definition: GraphBBTime.h:67
String _graphs_dir_name
Definition: GraphBBTime.h:150
Abstract class to represent the registered processors.
Definition: Registration.h:80
Représentation of a processor (to be used to build a ParExeGraph).
Definition: ParExeProc.h:195
elm::io::Output * _output
Definition: GraphBBTime.h:149
Definition: Registration.h:138
const int end
Definition: Registration.h:42
elm::genstruct::Vector< Resource * > _hw_resources
Definition: GraphBBTime.h:158
elm::String name(void)
Definition: ParExeProc.h:115
~PathContext()
Definition: GraphBBTime.h:103
void setPenalty(cache_penalty_type_t type, int value)
Definition: CachePenalty.h:50
genstruct::AllocatedTable< LBlock * > * lbs
Definition: GraphBBTime.h:71
Definition: ParExeGraph.h:128
ParExeSequence * buildSequence(PathContext *ctxt)
Definition: GraphBBTime.h:418
Definition: categories.h:41
Description of a processor pipeline.
Definition: Processor.h:136
Definition: Resource.h:61
BasicBlock * hd
Definition: GraphBBTime.h:72
Identifier< CachePenalty * > ICACHE_PENALTY
Edge * _edge
Definition: GraphBBTime.h:86
virtual void configureMem(WorkSpace *ws)
Definition: GraphBBTime.h:166
code_part_t
Definition: ParExeGraph.h:50
WorkSpace * _ws
Definition: GraphBBTime.h:145
dtd::Element bb(dtd::make("bb", _BB).attr(id).attr(address).attr(size))
int countInstructions(void) const
Definition: BasicBlock.h:182
Identifier< int > TIME
AutoStringStartup & _
void addLast(const T &value)
const int provide
Definition: Registration.h:44
Control Flow Graph representation.
Definition: CFG.h:42
Class to represent the whole memory of the platform.
Definition: Memory.h:173
void addBlock(BasicBlock *new_bb, Edge *edge)
Definition: GraphBBTime.h:106
StringOption proc(command, 'p',"processor","used processor","path","")
void dump(elm::io::Output &out)
Definition: CachePenalty.h:55
uint32 size
bool isEntry(void) const
Test if the basic block is the CFG entry.
Definition: BasicBlock.h:136
Definition: ParExeProc.h:171
Definition: Resource.h:56
virtual void computeDefaultTimingContextForICache(TimingContext *dtctxt, ParExeSequence *seq)
Definition: GraphBBTime.h:598
BasicBlock * _bb
Definition: GraphBBTime.h:85
Definition: GraphBBTime.h:41
Definition: categories.h:43
void analyzePathContext(PathContext *ctxt, int context_index)
Definition: GraphBBTime.h:628
void outputGraph(G *graph, int bb_number, int context_number, int case_number, const string &info="")
Output the given graph in the directory configured by GRAPHS_OUTPUT_DIRECTORY.
Definition: GraphBBTime.h:436
Identifier< elm::system::Path > CACHE_CONFIG_PATH
Gives the path of file containing the cache configuration.
bool isExit(void) const
Test if the basic block is the CFG exit.
Definition: BasicBlock.h:137
const category_t INVALID_CATEGORY
Definition: categories.h:78
elm::StringBuffer buf
Definition: util_fft_lexer.cc:640
Identifier< String > GRAPHS_OUTPUT_DIRECTORY
int numBlocks()
Definition: GraphBBTime.h:117
int numInsts()
Definition: GraphBBTime.h:115
int i
Definition: GraphBBTime.h:73
virtual void processWorkSpace(WorkSpace *fw)
Process the given framework.
Definition: proc_CFGProcessor.cpp:80
bool _do_consider_icache
Definition: GraphBBTime.h:154
const hard::Memory * mem
Definition: GraphBBTime.h:155
Definition: ParExeGraph.h:169
A workspace represents a program, its run-time and all information about WCET computation or any othe...
Definition: WorkSpace.h:67
void processWorkSpace(WorkSpace *ws)
Process the given framework.
Definition: GraphBBTime.h:268
This class contains the configuration of a level of cache of processor.
Definition: Cache.h:34
Definition: Resource.h:71
Definition: CachePenalty.h:33
static bool dominates(BasicBlock *bb1, BasicBlock *bb2)
Test if the first basic block dominates the second one.
Definition: util_Dominance.cpp:164
The representation of an address in OTAWA.
Definition: base.h:54
category_t
Definition: categories.h:37
bool isEmpty(void) const
BasicBlock * bb
Definition: GraphBBTime.h:70
int number(void) const
Get the number hooked on this basic block, that is, value of ID_Index property.
Definition: BasicBlock.h:146
const int require
Definition: Registration.h:43
virtual address_t address(void) const =0
Get the address of the item .
inst(void)
Definition: inst.h:118
virtual int memoryLatency(Address addr) const
Definition: GraphBBTime.h:200
const category_t FIRST_MISS
Definition: categories.h:81
bool isEmpty()
Definition: ParExeGraph.h:193
int _num_bbs
Definition: GraphBBTime.h:84
static Registration< GraphBBTime< G > > reg
Definition: GraphBBTime.h:174
ParExeStage * firstStage()
Definition: ParExeProc.h:167
A sequence of ParExeInstruction for which a ParExeGraph will be built.
Definition: ParExeGraph.h:125
Definition: ParExeProc.h:89
Representation of a pipeline (list of stages).
Definition: ParExeProc.h:157
Definition: ParExeGraph.h:52
BasicBlockIterator(const PathContext &ctxt)
Definition: GraphBBTime.h:133
Definition: BasicBlock.h:160
SilentFeature MEMORY_FEATURE
This feature ensures we have obtained the memory configuration of the system.
Definition: ParExeGraph.h:142
This class represents edges in the CFG representation.
Definition: Edge.h:33
Identifier< category_t > & CATEGORY
Definition: cache_categories.cpp:160
dtd::Element cfg(dtd::make("cfg", _CFG).attr(id).content((entry,*bb, exit,*edge)))
This basic block processor computes the basic block execution time using the execution graph method d...
Definition: GraphBBTime.h:143
Definition: CachePenalty.h:33
Identifier< genstruct::AllocatedTable< LBlock * > * > BB_LBLOCKS
This property is used for storing the list of L-Blocks of a BasicBlock.
void addNodeLatency(NodeLatency *nl)
Definition: ParExeGraph.h:191
This is the minimal definition of a basic block.
Definition: BasicBlock.h:43
Definition: Resource.h:37
BasicBlock * lastBlock()
Definition: GraphBBTime.h:119
A bank in the memory.
Definition: Memory.h:86
int latency(void) const
Get the default latency for accessing this bank.
Definition: Memory.h:120
void dump(io::Output &output)
Definition: GraphBBTime.h:125
Definition: categories.h:42
This class represents assembly instruction of a piece of code.
Definition: Inst.h:62
const int base
Definition: Registration.h:47
LBlockManager(void)
Definition: GraphBBTime.h:44
BasicBlock * header(int index)
Definition: CachePenalty.h:47
Instruction as presented in the ParExeGraph.
Definition: ParExeGraph.h:63
PathContext(BasicBlock *bb)
Definition: GraphBBTime.h:88
int penalty(cache_penalty_type_t type)
Definition: CachePenalty.h:52
This a list of properties.
Definition: PropList.h:63
OutStream * _output_stream
Definition: GraphBBTime.h:148
ParExeProc * _microprocessor
Definition: GraphBBTime.h:157
This class is used for returning exceptions from the processors.
Definition: ProcessorException.h:17
Identifier< ot::time > TIME
This identifier is used for storing the time of execution in cycles (int) of the program area it appl...
virtual void BuildVectorOfHwResources()
Definition: GraphBBTime.h:287
This class can be used to express the penalties due to the instruction cache.
Definition: CachePenalty.h:31
Identifier< const CacheConfiguration * > CACHE_CONFIGURATION
Current configuration.
int width(void) const
Definition: ParExeProc.h:114
void addLast(const T &value)
virtual void configure(const PropList &props)
Configure the current processor.
Definition: proc_CFGProcessor.cpp:151
PropList _props
Definition: GraphBBTime.h:146
void setHeader(int index, BasicBlock *bb)
Definition: CachePenalty.h:45
Definition: CachePenalty.h:33
void setType(CachePenalty::cache_penalty_type_t type)
Definition: ParExeGraph.h:201
Edge * edge()
Definition: GraphBBTime.h:123
bool _do_output_graphs
Definition: GraphBBTime.h:153
Definition: ParExeGraph.h:51
static MetaRegistration reg
Definition: CFGProcessor.h:43
Definition: GraphBBTime.h:131
Definition: ParExeGraph.h:154
Identifier< BasicBlock * > CATEGORY_HEADER
In the case of a FIRST_HIT (or FIRST_MISS) property, contains the header of the loop causing the HIT ...
SilentFeature PROCESSOR_FEATURE
This feature ensures we have obtained the memory configuration of the system.
virtual void buildFMTimingContextListForICache(elm::genstruct::SLList< TimingContext * > *list, ParExeSequence *seq)
Definition: GraphBBTime.h:490
Definition: CachePenalty.h:33
Address address(void) const
Definition: BasicBlock.h:140
virtual int cacheMissPenalty(Address addr) const
Definition: GraphBBTime.h:193
SilentFeature BB_TIME_FEATURE
This feature ensures that the execution time of each basic block has been computed.
String toString(void)
void processBB(WorkSpace *ws, CFG *cfg, BasicBlock *bb)
Perform the work of the given basic block.
Definition: GraphBBTime.h:857
Iterator for instructions in the basic block.
Definition: BasicBlock.h:70
Definition: GraphBBTime.h:80