remove #ifdef HAVE_CONFIG_Hs
[libfirm] / ir / be / belistsched.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       Primitive list scheduling with different node selectors.
23  * @author      Sebastian Hack
24  * @date        20.10.2004
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include <stdio.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <limits.h>
33
34 #include "benode_t.h"
35 #include "be_t.h"
36
37 #include "obst.h"
38 #include "list.h"
39 #include "iterator.h"
40
41 #include "iredges_t.h"
42 #include "irgwalk.h"
43 #include "irnode_t.h"
44 #include "irmode_t.h"
45 #include "irdump.h"
46 #include "irprintf_t.h"
47 #include "array.h"
48 #include "debug.h"
49 #include "irtools.h"
50
51 #include "bemodule.h"
52 #include "besched_t.h"
53 #include "beutil.h"
54 #include "belive_t.h"
55 #include "belistsched.h"
56 #include "beschedmris.h"
57 #include "beschedrss.h"
58 #include "bearch_t.h"
59 #include "bestat.h"
60 #include "beirg_t.h"
61
62 #include "lc_opts.h"
63 #include "lc_opts_enum.h"
64
65 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL);
66
67 #define BE_SCHED_NODE(irn) (be_is_Keep(irn) || be_is_CopyKeep(irn) || be_is_RegParams(irn))
68
69 enum {
70         BE_SCHED_SELECT_TRIVIAL,
71         BE_SCHED_SELECT_REGPRESS,
72         BE_SCHED_SELECT_MUCHNIK,
73         BE_SCHED_SELECT_HEUR,
74         BE_SCHED_SELECT_HMUCHNIK,
75         BE_SCHED_SELECT_RANDOM,
76         BE_SCHED_SELECT_NORMAL,
77 };
78
79 enum {
80         BE_SCHED_PREP_NONE = 0,
81         BE_SCHED_PREP_MRIS = 2,
82         BE_SCHED_PREP_RSS  = 3
83 };
84
85 typedef struct _list_sched_options_t {
86         int select;  /**< the node selector */
87         int prep;    /**< schedule preparation */
88 } list_sched_options_t;
89
90 static list_sched_options_t list_sched_options = {
91         BE_SCHED_SELECT_NORMAL,   /* mueller heuristic selector */
92         BE_SCHED_PREP_NONE,       /* no scheduling preparation */
93 };
94
95 /* schedule selector options. */
96 static const lc_opt_enum_int_items_t sched_select_items[] = {
97         { "trivial",  BE_SCHED_SELECT_TRIVIAL  },
98         { "random",   BE_SCHED_SELECT_RANDOM   },
99         { "regpress", BE_SCHED_SELECT_REGPRESS },
100         { "normal",   BE_SCHED_SELECT_NORMAL   },
101         { "muchnik",  BE_SCHED_SELECT_MUCHNIK  },
102         { "heur",     BE_SCHED_SELECT_HEUR     },
103         { "hmuchnik", BE_SCHED_SELECT_HMUCHNIK },
104         { NULL,       0 }
105 };
106
107 /* schedule preparation options. */
108 static const lc_opt_enum_int_items_t sched_prep_items[] = {
109         { "none", BE_SCHED_PREP_NONE },
110         { "mris", BE_SCHED_PREP_MRIS },
111         { "rss",  BE_SCHED_PREP_RSS  },
112         { NULL,   0 }
113 };
114
115 static lc_opt_enum_int_var_t sched_select_var = {
116         &list_sched_options.select, sched_select_items
117 };
118
119 static lc_opt_enum_int_var_t sched_prep_var = {
120         &list_sched_options.prep, sched_prep_items
121 };
122
123 static const lc_opt_table_entry_t list_sched_option_table[] = {
124         LC_OPT_ENT_ENUM_PTR("prep",   "schedule preparation",   &sched_prep_var),
125         LC_OPT_ENT_ENUM_PTR("select", "node selector",          &sched_select_var),
126         LC_OPT_LAST
127 };
128
129 /**
130  * All scheduling info needed per node.
131  */
132 typedef struct _sched_irn_t {
133         unsigned num_not_sched_user; /**< The number of not yet scheduled users of this node */
134         unsigned already_sched : 1;  /**< Set if this node is already scheduled */
135 } sched_irn_t;
136
137 /**
138  * Scheduling environment for the whole graph.
139  */
140 typedef struct _sched_env_t {
141         sched_irn_t *sched_info;                    /**< scheduling info per node */
142         const list_sched_selector_t *selector;      /**< The node selector. */
143         const arch_env_t *arch_env;                 /**< The architecture environment. */
144         const ir_graph *irg;                        /**< The graph to schedule. */
145         void *selector_env;                         /**< A pointer to give to the selector. */
146 } sched_env_t;
147
148 /**
149  * Environment for a block scheduler.
150  */
151 typedef struct _block_sched_env_t {
152         sched_irn_t *sched_info;                    /**< scheduling info per node, copied from the global scheduler object */
153         ir_nodeset_t cands;                         /**< the set of candidates */
154         ir_node *block;                             /**< the current block */
155         sched_env_t *sched_env;                     /**< the scheduler environment */
156         ir_nodeset_t live;                          /**< simple liveness during scheduling */
157         const list_sched_selector_t *selector;
158         void *selector_block_env;
159 } block_sched_env_t;
160
161 /**
162  * Returns non-zero if a node must be placed in the schedule.
163  */
164 static INLINE int must_appear_in_schedule(const list_sched_selector_t *sel, void *block_env, const ir_node *irn)
165 {
166         int res = -1;
167
168         /* if there are no uses, don't schedule */
169         if (get_irn_n_edges(irn) < 1)
170                 return 0;
171
172         /* else ask the scheduler */
173         if (sel->to_appear_in_schedule)
174                 res = sel->to_appear_in_schedule(block_env, irn);
175
176         return res >= 0 ? res : ((to_appear_in_schedule(irn) || BE_SCHED_NODE(irn)) && ! is_Unknown(irn));
177 }
178
179 /**
180  * Returns non-zero if the node is already scheduled
181  */
182 static INLINE int is_already_scheduled(block_sched_env_t *env, ir_node *n)
183 {
184         int idx = get_irn_idx(n);
185
186         assert(idx < ARR_LEN(env->sched_info));
187         return env->sched_info[idx].already_sched;
188 }
189
190 /**
191  * Mark a node as already scheduled
192  */
193 static INLINE void set_already_scheduled(block_sched_env_t *env, ir_node *n)
194 {
195         int idx = get_irn_idx(n);
196
197         assert(idx < ARR_LEN(env->sched_info));
198         env->sched_info[idx].already_sched = 1;
199 }
200
201 static void add_to_sched(block_sched_env_t *env, ir_node *irn);
202
203 /**
204  * Try to put a node in the ready set.
205  * @param env   The block scheduler environment.
206  * @param pred  The previous scheduled node.
207  * @param irn   The node to make ready.
208  * @return 1, if the node could be made ready, 0 else.
209  */
210 static INLINE int make_ready(block_sched_env_t *env, ir_node *pred, ir_node *irn)
211 {
212         int i, n;
213
214         /* Blocks cannot be scheduled. */
215         if (is_Block(irn) || get_irn_n_edges(irn) == 0)
216                 return 0;
217
218         /*
219          * Check, if the given ir node is in a different block as the
220          * currently scheduled one. If that is so, don't make the node ready.
221          */
222         if (env->block != get_nodes_block(irn))
223                 return 0;
224
225         for (i = 0, n = get_irn_ins_or_deps(irn); i < n; ++i) {
226                 ir_node *op = get_irn_in_or_dep(irn, i);
227
228                 /* if irn is an End we have keep-alives and op might be a block, skip that */
229                 if (is_Block(op)) {
230                         assert(is_End(irn));
231                         continue;
232                 }
233
234                 /* If the operand is local to the scheduled block and not yet
235                  * scheduled, this nodes cannot be made ready, so exit. */
236                 if (! is_already_scheduled(env, op) && get_nodes_block(op) == env->block)
237                         return 0;
238         }
239
240         if (! must_appear_in_schedule(env->selector, env, irn)) {
241                 add_to_sched(env, irn);
242                 DB((dbg, LEVEL_3, "\tmaking immediately available: %+F\n", irn));
243         } else {
244                 ir_nodeset_insert(&env->cands, irn);
245
246                 /* Notify selector about the ready node. */
247                 if (env->selector->node_ready)
248                         env->selector->node_ready(env->selector_block_env, irn, pred);
249
250                 DB((dbg, LEVEL_2, "\tmaking ready: %+F\n", irn));
251         }
252
253     return 1;
254 }
255
256 /**
257  * Try, to make all users of a node ready.
258  * In fact, a usage node can only be made ready, if all its operands
259  * have already been scheduled yet. This is checked by make_ready().
260  * @param env The block schedule environment.
261  * @param irn The node, which usages (successors) are to be made ready.
262  */
263 static void make_users_ready(block_sched_env_t *env, ir_node *irn)
264 {
265         const ir_edge_t *edge;
266
267         /* make all data users ready */
268         foreach_out_edge(irn, edge) {
269                 ir_node *user = get_edge_src_irn(edge);
270
271                 if (! is_Phi(user))
272                         make_ready(env, irn, user);
273         }
274
275         /* and the dependent nodes as well */
276         foreach_out_edge_kind(irn, edge, EDGE_KIND_DEP) {
277                 ir_node *user = get_edge_src_irn(edge);
278
279                 if (! is_Phi(user))
280                         make_ready(env, irn, user);
281         }
282 }
283
284 /**
285  * Returns the number of not yet schedules users.
286  */
287 static INLINE int get_irn_not_sched_user(block_sched_env_t *env, ir_node *n) {
288         int idx = get_irn_idx(n);
289
290         assert(idx < ARR_LEN(env->sched_info));
291         return env->sched_info[idx].num_not_sched_user;
292 }
293
294 /**
295  * Sets the number of not yet schedules users.
296  */
297 static INLINE void set_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
298         int idx = get_irn_idx(n);
299
300         assert(idx < ARR_LEN(env->sched_info));
301         env->sched_info[idx].num_not_sched_user = num;
302 }
303
304 /**
305  * Add @p num to the number of not yet schedules users and returns the result.
306  */
307 static INLINE int add_irn_not_sched_user(block_sched_env_t *env, ir_node *n, int num) {
308         int idx = get_irn_idx(n);
309
310         assert(idx < ARR_LEN(env->sched_info));
311         env->sched_info[idx].num_not_sched_user += num;
312         return env->sched_info[idx].num_not_sched_user;
313 }
314
315 /**
316  * Returns the number of users of a node having mode datab.
317  */
318 static int get_num_successors(ir_node *irn) {
319         int             sum = 0;
320         const ir_edge_t *edge;
321
322         if (get_irn_mode(irn) == mode_T) {
323                 /* for mode_T nodes: count the users of all Projs */
324                 foreach_out_edge(irn, edge) {
325                         ir_node *proj = get_edge_src_irn(edge);
326                         ir_mode *mode = get_irn_mode(proj);
327
328                         if (mode == mode_T) {
329                                 sum += get_num_successors(proj);
330                         } else if (mode_is_datab(mode)) {
331                                 sum += get_irn_n_edges(proj);
332                         }
333                 }
334         }
335         else {
336                 /* do not count keep-alive edges */
337                 foreach_out_edge(irn, edge) {
338                         if (get_irn_opcode(get_edge_src_irn(edge)) != iro_End)
339                                 sum++;
340                 }
341         }
342
343         return sum;
344 }
345
346 /**
347  * Adds irn to @p live, updates all inputs that this user is scheduled
348  * and counts all of its non scheduled users.
349  */
350 static void update_sched_liveness(block_sched_env_t *env, ir_node *irn) {
351         int i;
352
353         /* ignore Projs */
354         if (is_Proj(irn))
355                 return;
356
357         for (i = get_irn_ins_or_deps(irn) - 1; i >= 0; --i) {
358                 ir_node *in = get_irn_in_or_dep(irn, i);
359
360                 /* if in is a proj: update predecessor */
361                 in = skip_Proj(in);
362
363                 /* if in is still in the live set: reduce number of users by one */
364                 if (ir_nodeset_contains(&env->live, in)) {
365                         if (add_irn_not_sched_user(env, in, -1) <= 0)
366                                 ir_nodeset_remove(&env->live, in);
367                 }
368         }
369
370         /*
371                 get_num_successors returns the number of all users. This includes
372                 users in different blocks as well. As the each block is scheduled separately
373                 the liveness info of those users will not be updated and so these
374                 users will keep up the register pressure as it is desired.
375         */
376         i = get_num_successors(irn);
377         if (i > 0) {
378                 set_irn_not_sched_user(env, irn, i);
379                 ir_nodeset_insert(&env->live, irn);
380         }
381 }
382
383 /**
384  * Append an instruction to a schedule.
385  * @param env The block scheduling environment.
386  * @param irn The node to add to the schedule.
387  * @return    The given node.
388  */
389 static void add_to_sched(block_sched_env_t *env, ir_node *irn)
390 {
391     /* If the node consumes/produces data, it is appended to the schedule
392      * list, otherwise, it is not put into the list */
393     if (must_appear_in_schedule(env->selector, env->selector_block_env, irn)) {
394                 update_sched_liveness(env, irn);
395                 sched_add_before(env->block, irn);
396
397                 DBG((dbg, LEVEL_2, "\tadding %+F\n", irn));
398
399                 /* Remove the node from the ready set */
400                 ir_nodeset_remove(&env->cands, irn);
401     }
402
403         /* notify the selector about the finally selected node. */
404         if (env->selector->node_selected)
405                 env->selector->node_selected(env->selector_block_env, irn);
406
407     /* Insert the node in the set of all available scheduled nodes. */
408     set_already_scheduled(env, irn);
409
410         make_users_ready(env, irn);
411 }
412
413 /**
414  * Perform list scheduling on a block.
415  *
416  * Note, that the caller must compute a linked list of nodes in the block
417  * using the link field before calling this function.
418  *
419  * Also the outs must have been computed.
420  *
421  * @param block The block node.
422  * @param env Scheduling environment.
423  */
424 static void list_sched_block(ir_node *block, void *env_ptr)
425 {
426         sched_env_t *env                      = env_ptr;
427         const list_sched_selector_t *selector = env->selector;
428         ir_node *start_node                   = get_irg_start(get_irn_irg(block));
429
430         block_sched_env_t be;
431         const ir_edge_t *edge;
432         ir_node *irn;
433         int j, m;
434
435         /* Initialize the block's list head that will hold the schedule. */
436         sched_init_block(block);
437
438         /* Initialize the block scheduling environment */
439         be.sched_info = env->sched_info;
440         be.block      = block;
441         ir_nodeset_init_size(&be.cands, get_irn_n_edges(block));
442         ir_nodeset_init_size(&be.live, get_irn_n_edges(block));
443         be.selector   = selector;
444         be.sched_env  = env;
445
446         DBG((dbg, LEVEL_1, "scheduling %+F\n", block));
447
448         if (selector->init_block)
449                 be.selector_block_env = selector->init_block(env->selector_env, block);
450
451         /* Then one can add all nodes are ready to the set. */
452         foreach_out_edge(block, edge) {
453                 ir_node   *irn = get_edge_src_irn(edge);
454                 ir_opcode code = get_irn_opcode(irn);
455                 int users;
456
457                 if (code == iro_End) {
458                         /* Skip the end node because of keep-alive edges. */
459                         continue;
460                 } else if (code == iro_Block) {
461                         /* A Block-Block edge. This should be the MacroBlock
462                          * edge, ignore it. */
463                         assert(get_Block_MacroBlock(irn) == block && "Block-Block edge found");
464                         continue;
465                 }
466
467                 users = get_irn_n_edges(irn);
468                 if (users == 0)
469                         continue;
470                 else if (users == 1) { /* ignore nodes that are only hold by the anchor */
471                         const ir_edge_t *edge = get_irn_out_edge_first_kind(irn, EDGE_KIND_NORMAL);
472                         ir_node *user = get_edge_src_irn(edge);
473                         if (is_Anchor(user))
474                                 continue;
475                 }
476
477                 if (is_Phi(irn)) {
478                         /*
479                                 Phi functions are scheduled immediately, since they     only
480                                 transfer data flow from the predecessors to this block.
481                         */
482                         add_to_sched(&be, irn);
483                 }
484                 else if (irn == start_node) {
485                         /* The start block will be scheduled as the first node */
486                         add_to_sched(&be, irn);
487                 }
488                 else {
489                         /* Other nodes must have all operands in other blocks to be made
490                          * ready */
491                         int ready = 1;
492
493                         /* Check, if the operands of a node are not local to this block */
494                         for (j = 0, m = get_irn_ins_or_deps(irn); j < m; ++j) {
495                                 ir_node *operand = get_irn_in_or_dep(irn, j);
496
497                                 if (get_nodes_block(operand) == block) {
498                                         ready = 0;
499                                         break;
500                                 } else {
501                                         /* live in values increase register pressure */
502                                         ir_nodeset_insert(&be.live, operand);
503                                 }
504                         }
505
506                         /* Make the node ready, if all operands live in a foreign block */
507                         if (ready) {
508                                 DBG((dbg, LEVEL_2, "\timmediately ready: %+F\n", irn));
509                                 make_ready(&be, NULL, irn);
510                         }
511                 }
512         }
513
514         /* Iterate over all remaining nodes */
515         while (ir_nodeset_size(&be.cands) > 0) {
516                 ir_nodeset_iterator_t iter;
517
518                 /* Keeps must be scheduled immediately */
519                 foreach_ir_nodeset(&be.cands, irn, iter) {
520                         if (be_is_Keep(irn) || be_is_CopyKeep(irn) || is_Sync(irn)) {
521                                 break;
522                         }
523                 }
524
525                 if (! irn) {
526                         /* Keeps must be immediately scheduled */
527                         irn = be.selector->select(be.selector_block_env, &be.cands, &be.live);
528                 }
529
530                 DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn));
531
532                 /* Add the node to the schedule. */
533                 add_to_sched(&be, irn);
534
535                 /* remove the scheduled node from the ready list. */
536                 ir_nodeset_remove(&be.cands, irn);
537         }
538
539         if (selector->finish_block)
540                 selector->finish_block(be.selector_block_env);
541
542         ir_nodeset_destroy(&be.cands);
543         ir_nodeset_destroy(&be.live);
544 }
545
546 /* List schedule a graph. */
547 void list_sched(be_irg_t *birg, be_options_t *be_opts)
548 {
549         const arch_env_t *arch_env = birg->main_env->arch_env;
550         ir_graph         *irg      = birg->irg;
551
552         int num_nodes;
553         sched_env_t env;
554         mris_env_t *mris = NULL;
555         list_sched_selector_t sel;
556
557         (void)be_opts;
558
559         /* Select a scheduler based on backend options */
560         switch (list_sched_options.select) {
561                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
562                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
563                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
564                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
565                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
566                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
567                 default:
568                 case BE_SCHED_SELECT_HMUCHNIK: sel = trivial_selector;      break;
569         }
570
571 #if 1
572         /* Matze: This is very slow, we should avoid it to improve backend speed,
573          * we just have to make sure that we have no dangling out-edges at this
574          * point...
575          */
576
577         /* Assure, that we have no dangling out-edges to deleted stuff */
578         edges_deactivate(birg->irg);
579         edges_activate(birg->irg);
580 #endif
581
582         switch (list_sched_options.prep) {
583                 case BE_SCHED_PREP_MRIS:
584                         mris = be_sched_mris_preprocess(birg);
585                         break;
586                 case BE_SCHED_PREP_RSS:
587                         rss_schedule_preparation(birg);
588                         break;
589                 default:
590                         break;
591         }
592
593         num_nodes = get_irg_last_idx(irg);
594
595         /* initialize environment for list scheduler */
596         memset(&env, 0, sizeof(env));
597         env.selector   = arch_env_get_list_sched_selector(arch_env, &sel);
598         env.arch_env   = arch_env;
599         env.irg        = irg;
600         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
601
602         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
603
604         if (env.selector->init_graph)
605                 env.selector_env = env.selector->init_graph(env.selector, birg);
606
607         /* Schedule each single block. */
608         irg_block_walk_graph(irg, list_sched_block, NULL, &env);
609
610         if (env.selector->finish_graph)
611                 env.selector->finish_graph(env.selector_env);
612
613         if (list_sched_options.prep == BE_SCHED_PREP_MRIS)
614                 be_sched_mris_free(mris);
615
616         DEL_ARR_F(env.sched_info);
617 }
618
619 /* List schedule a block. */
620 void list_sched_single_block(const be_irg_t *birg, ir_node *block,
621                              be_options_t *be_opts)
622 {
623         const arch_env_t *arch_env = birg->main_env->arch_env;
624         ir_graph         *irg      = birg->irg;
625
626         int num_nodes;
627         sched_env_t env;
628         list_sched_selector_t sel;
629
630         (void)be_opts;
631
632         /* Select a scheduler based on backend options */
633         switch (list_sched_options.select) {
634                 case BE_SCHED_SELECT_TRIVIAL:  sel = trivial_selector;      break;
635                 case BE_SCHED_SELECT_RANDOM:   sel = random_selector;       break;
636                 case BE_SCHED_SELECT_REGPRESS: sel = reg_pressure_selector; break;
637                 case BE_SCHED_SELECT_MUCHNIK:  sel = muchnik_selector;      break;
638                 case BE_SCHED_SELECT_HEUR:     sel = heuristic_selector;    break;
639                 case BE_SCHED_SELECT_NORMAL:   sel = normal_selector;       break;
640                 default:
641                 case BE_SCHED_SELECT_HMUCHNIK: sel = trivial_selector;      break;
642         }
643
644         /* Assure, that the out edges are computed */
645         edges_deactivate(birg->irg);
646         edges_activate(birg->irg);
647
648         num_nodes = get_irg_last_idx(irg);
649
650         /* initialize environment for list scheduler */
651         memset(&env, 0, sizeof(env));
652         env.selector   = arch_env_get_list_sched_selector(arch_env, &sel);
653         env.arch_env   = arch_env;
654         env.irg        = irg;
655         env.sched_info = NEW_ARR_F(sched_irn_t, num_nodes);
656
657         memset(env.sched_info, 0, num_nodes * sizeof(env.sched_info[0]));
658
659         if (env.selector->init_graph)
660                 env.selector_env = env.selector->init_graph(env.selector, birg);
661
662         /* Schedule block. */
663         list_sched_block(block, &env);
664
665         if (env.selector->finish_graph)
666                 env.selector->finish_graph(env.selector_env);
667
668         DEL_ARR_F(env.sched_info);
669 }
670
671 /**
672  * Register list scheduler options.
673  */
674 void be_init_listsched(void) {
675         lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
676         lc_opt_entry_t *sched_grp = lc_opt_get_grp(be_grp, "listsched");
677
678         lc_opt_add_table(sched_grp, list_sched_option_table);
679
680         FIRM_DBG_REGISTER(dbg, "firm.be.sched");
681 }
682
683 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_listsched);