1 /* SimGrid Lua bindings */
3 /* Copyright (c) 2010. The SimGrid Team.
4 * All rights reserved. */
6 /* This program is free software; you can redistribute it and/or modify it
7 * under the terms of the license (GNU LGPL) which comes with this package. */
8 #include "simgrid_lua.h"
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(lua, bindings, "Lua Bindings");
12 #define TASK_MODULE_NAME "simgrid.Task"
13 #define HOST_MODULE_NAME "simgrid.Host"
14 // Surf ( bypass XML )
15 #define LINK_MODULE_NAME "simgrid.Link"
16 #define ROUTE_MODULE_NAME "simgrid.Route"
17 #define AS_MODULE_NAME "simgrid.AS"
18 #define TRACE_MODULE_NAME "simgrid.Trace"
20 /* ********************************************************************************* */
21 /* helper functions */
22 /* ********************************************************************************* */
23 static void stackDump(const char *msg, lua_State * L)
28 int top = lua_gettop(L);
31 p += sprintf(p, "STACK(top=%d): ", top);
33 for (i = 1; i <= top; i++) { /* repeat for each level */
34 int t = lua_type(L, i);
37 case LUA_TSTRING: /* strings */
38 p += sprintf(p, "`%s'", lua_tostring(L, i));
41 case LUA_TBOOLEAN: /* booleans */
42 p += sprintf(p, lua_toboolean(L, i) ? "true" : "false");
45 case LUA_TNUMBER: /* numbers */
46 p += sprintf(p, "%g", lua_tonumber(L, i));
50 p += sprintf(p, "Table");
53 default: /* other values */
54 p += sprintf(p, "???");
55 /* if ((ptr = luaL_checkudata(L,i,TASK_MODULE_NAME))) {
58 p+=printf(p,"%s", lua_typename(L, t));
63 p += sprintf(p, " "); /* put a separator */
65 INFO2("%s%s", msg, buff);
68 /** @brief ensures that a userdata on the stack is a task and returns the pointer inside the userdata */
69 static m_task_t checkTask(lua_State * L, int index)
72 luaL_checktype(L, index, LUA_TTABLE);
73 lua_getfield(L, index, "__simgrid_task");
74 pi = (m_task_t *) luaL_checkudata(L, -1, TASK_MODULE_NAME);
76 luaL_typerror(L, index, TASK_MODULE_NAME);
79 luaL_error(L, "null Task");
84 /* ********************************************************************************* */
85 /* wrapper functions */
86 /* ********************************************************************************* */
89 * A task is either something to compute somewhere, or something to exchange between two hosts (or both).
90 * It is defined by a computing amount and a message size.
98 * Construct an new task with the specified processing amount and amount
101 * @param name Task's name
103 * @param computeDuration A value of the processing amount (in flop) needed to process the task.
104 * If 0, then it cannot be executed with the execute() method.
105 * This value has to be >= 0.
107 * @param messageSize A value of amount of data (in bytes) needed to transfert this task.
108 * If 0, then it cannot be transfered with the get() and put() methods.
109 * This value has to be >= 0.
111 static int Task_new(lua_State * L)
113 const char *name = luaL_checkstring(L, 1);
114 int comp_size = luaL_checkint(L, 2);
115 int msg_size = luaL_checkint(L, 3);
116 m_task_t msg_task = MSG_task_create(name, comp_size, msg_size, NULL);
117 lua_newtable(L); /* create a table, put the userdata on top of it */
118 m_task_t *lua_task = (m_task_t *) lua_newuserdata(L, sizeof(m_task_t));
119 *lua_task = msg_task;
120 luaL_getmetatable(L, TASK_MODULE_NAME);
121 lua_setmetatable(L, -2);
122 lua_setfield(L, -2, "__simgrid_task"); /* put the userdata as field of the table */
123 /* remove the args from the stack */
130 static int Task_get_name(lua_State * L)
132 m_task_t tk = checkTask(L, -1);
133 lua_pushstring(L, MSG_task_get_name(tk));
137 static int Task_computation_duration(lua_State * L)
139 m_task_t tk = checkTask(L, -1);
140 lua_pushnumber(L, MSG_task_get_compute_duration(tk));
144 static int Task_execute(lua_State * L)
146 m_task_t tk = checkTask(L, -1);
147 int res = MSG_task_execute(tk);
148 lua_pushnumber(L, res);
152 static int Task_destroy(lua_State * L)
154 m_task_t tk = checkTask(L, -1);
155 int res = MSG_task_destroy(tk);
156 lua_pushnumber(L, res);
160 static int Task_send(lua_State * L)
162 //stackDump("send ",L);
163 m_task_t tk = checkTask(L, -2);
164 const char *mailbox = luaL_checkstring(L, -1);
165 lua_pop(L, 1); // remove the string so that the task is on top of it
166 MSG_task_set_data(tk, L); // Copy my stack into the task, so that the receiver can copy the lua task directly
167 MSG_error_t res = MSG_task_send(tk, mailbox);
168 while (MSG_task_get_data(tk) != NULL) // Don't mess up with my stack: the receiver didn't copy the data yet
169 MSG_process_sleep(0); // yield
174 ERROR0("MSG_task_send failed : Timeout");
176 case MSG_TRANSFER_FAILURE:
177 ERROR0("MSG_task_send failed : Transfer Failure");
179 case MSG_HOST_FAILURE:
180 ERROR0("MSG_task_send failed : Host Failure ");
184 ("MSG_task_send failed : Unexpected error , please report this bug");
190 static int Task_recv(lua_State * L)
193 const char *mailbox = luaL_checkstring(L, -1);
194 MSG_error_t res = MSG_task_receive(&tk, mailbox);
196 lua_State *sender_stack = MSG_task_get_data(tk);
197 lua_xmove(sender_stack, L, 1); // copy the data directly from sender's stack
198 MSG_task_set_data(tk, NULL);
203 ERROR0("MSG_task_receive failed : Timeout");
205 case MSG_TRANSFER_FAILURE:
206 ERROR0("MSG_task_receive failed : Transfer Failure");
208 case MSG_HOST_FAILURE:
209 ERROR0("MSG_task_receive failed : Host Failure ");
213 ("MSG_task_receive failed : Unexpected error , please report this bug");
220 static const luaL_reg Task_methods[] = {
222 {"name", Task_get_name},
223 {"computation_duration", Task_computation_duration},
224 {"execute", Task_execute},
225 {"destroy", Task_destroy},
231 static int Task_gc(lua_State * L)
233 m_task_t tk = checkTask(L, -1);
235 MSG_task_destroy(tk);
239 static int Task_tostring(lua_State * L)
241 lua_pushfstring(L, "Task :%p", lua_touserdata(L, 1));
245 static const luaL_reg Task_meta[] = {
247 {"__tostring", Task_tostring},
254 static m_host_t checkHost(lua_State * L, int index)
257 luaL_checktype(L, index, LUA_TTABLE);
258 lua_getfield(L, index, "__simgrid_host");
259 pi = (m_host_t *) luaL_checkudata(L, -1, HOST_MODULE_NAME);
261 luaL_typerror(L, index, HOST_MODULE_NAME);
264 luaL_error(L, "null Host");
269 static int Host_get_by_name(lua_State * L)
271 const char *name = luaL_checkstring(L, 1);
272 DEBUG0("Getting Host from name...");
273 m_host_t msg_host = MSG_get_host_by_name(name);
275 luaL_error(L, "null Host : MSG_get_host_by_name failled");
277 lua_newtable(L); /* create a table, put the userdata on top of it */
278 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
279 *lua_host = msg_host;
280 luaL_getmetatable(L, HOST_MODULE_NAME);
281 lua_setmetatable(L, -2);
282 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
283 /* remove the args from the stack */
289 static int Host_get_name(lua_State * L)
291 m_host_t ht = checkHost(L, -1);
292 lua_pushstring(L, MSG_host_get_name(ht));
296 static int Host_number(lua_State * L)
298 lua_pushnumber(L, MSG_get_host_number());
302 static int Host_at(lua_State * L)
304 int index = luaL_checkinteger(L, 1);
305 m_host_t host = MSG_get_host_table()[index - 1]; // lua indexing start by 1 (lua[1] <=> C[0])
306 lua_newtable(L); /* create a table, put the userdata on top of it */
307 m_host_t *lua_host = (m_host_t *) lua_newuserdata(L, sizeof(m_host_t));
309 luaL_getmetatable(L, HOST_MODULE_NAME);
310 lua_setmetatable(L, -2);
311 lua_setfield(L, -2, "__simgrid_host"); /* put the userdata as field of the table */
316 static int Host_self(lua_State * L)
318 m_host_t host = MSG_host_self();
320 m_host_t *lua_host =(m_host_t *)lua_newuserdata(L,sizeof(m_host_t));
322 luaL_getmetatable(L, HOST_MODULE_NAME);
323 lua_setmetatable(L, -2);
324 lua_setfield(L, -2, "__simgrid_host");
329 static int Host_get_property_value(lua_State * L)
331 m_host_t ht = checkHost(L, -2);
332 const char *prop = luaL_checkstring(L, -1);
333 lua_pushstring(L,MSG_host_get_property_value(ht,prop));
337 /* ********************************************************************************* */
338 /* lua_stub_generator functions */
339 /* ********************************************************************************* */
341 xbt_dict_t process_function_set;
342 xbt_dynar_t process_list;
343 xbt_dict_t machine_set;
344 static s_process_t process;
346 void s_process_free(void *process)
348 s_process_t *p = (s_process_t *) process;
350 for (i = 0; i < p->argc; i++)
356 static int gras_add_process_function(lua_State * L)
359 const char *process_host = luaL_checkstring(L, 1);
360 const char *process_function = luaL_checkstring(L, 2);
362 if (xbt_dict_is_empty(machine_set)
363 || xbt_dict_is_empty(process_function_set)
364 || xbt_dynar_is_empty(process_list)) {
365 process_function_set = xbt_dict_new();
366 process_list = xbt_dynar_new(sizeof(s_process_t), s_process_free);
367 machine_set = xbt_dict_new();
370 xbt_dict_set(machine_set, process_host, NULL, NULL);
371 xbt_dict_set(process_function_set, process_function, NULL, NULL);
374 process.argv = xbt_new(char *, 1);
375 process.argv[0] = xbt_strdup(process_function);
376 process.host = strdup(process_host);
379 while (lua_next(L, 3) != 0) {
380 arg = lua_tostring(L, -1);
383 xbt_realloc(process.argv, (process.argc) * sizeof(char *));
384 process.argv[(process.argc) - 1] = xbt_strdup(arg);
386 DEBUG2("index = %f , arg = %s \n", lua_tonumber(L, -2),
387 lua_tostring(L, -1));
391 //add to the process list
392 xbt_dynar_push(process_list, &process);
399 static int gras_generate(lua_State * L)
401 const char *project_name = luaL_checkstring(L, 1);
402 generate_sim(project_name);
403 generate_rl(project_name);
404 generate_makefile_local(project_name);
408 /***********************************
410 **********************************/
411 static int trace_start(lua_State *L)
417 static int trace_category(lua_State * L)
419 const char * category = luaL_checkstring(L, 1);
420 TRACE_category(category);
424 static int trace_set_task_category(lua_State *L)
426 m_task_t tk = checkTask(L, -2);
427 const char *category = luaL_checkstring(L, -1);
428 TRACE_msg_set_task_category(tk,category);
432 static int trace_end(lua_State *L)
437 //***********Register Methods *******************************************//
441 static const luaL_reg Host_methods[] = {
442 {"getByName", Host_get_by_name},
443 {"name", Host_get_name},
444 {"number", Host_number},
447 {"getPropValue",Host_get_property_value},
448 // Bypass XML Methods
449 {"new", console_add_host},
450 {"setFunction", console_set_function},
454 static int Host_gc(lua_State * L)
456 m_host_t ht = checkHost(L, -1);
462 static int Host_tostring(lua_State * L)
464 lua_pushfstring(L, "Host :%p", lua_touserdata(L, 1));
468 static const luaL_reg Host_meta[] = {
470 {"__tostring", Host_tostring},
477 static const luaL_reg AS_methods[] = {
478 {"new", console_add_AS},
486 static const luaL_reg Link_methods[] = {
487 {"new", console_add_link},
494 static const luaL_reg Route_methods[] = {
495 {"new", console_add_route},
502 static const luaL_reg Trace_methods[] = {
503 {"start",trace_start},
504 {"category",trace_category},
505 {"setTaskCategory",trace_set_task_category},
506 {"finish",trace_end},
510 * Environment related
513 extern lua_State *simgrid_lua_state;
515 static int run_lua_code(int argc, char **argv)
517 DEBUG1("Run lua code %s", argv[0]);
518 lua_State *L = lua_newthread(simgrid_lua_state);
519 int ref = luaL_ref(simgrid_lua_state, LUA_REGISTRYINDEX); // protect the thread from being garbage collected
522 /* Start the co-routine */
523 lua_getglobal(L, argv[0]);
524 xbt_assert1(lua_isfunction(L, -1),
525 "The lua function %s does not seem to exist", argv[0]);
527 // push arguments onto the stack
529 for (i = 1; i < argc; i++)
530 lua_pushstring(L, argv[i]);
532 // Call the function (in resume)
533 xbt_assert2(lua_pcall(L, argc - 1, 1, 0) == 0,
534 "error running function `%s': %s", argv[0], lua_tostring(L,
537 /* retrieve result */
538 if (lua_isnumber(L, -1)) {
539 res = lua_tonumber(L, -1);
540 lua_pop(L, 1); /* pop returned value */
543 luaL_unref(simgrid_lua_state, LUA_REGISTRYINDEX, ref);
544 DEBUG1("Execution of lua code %s is over", (argv ? argv[0] : "(null)"));
548 static int launch_application(lua_State * L)
550 const char *file = luaL_checkstring(L, 1);
551 MSG_function_register_default(run_lua_code);
552 MSG_launch_application(file);
556 #include "simix/simix.h" //FIXME: KILLME when debugging on simix internals become useless
557 static int create_environment(lua_State * L)
559 const char *file = luaL_checkstring(L, 1);
560 DEBUG1("Loading environment file %s", file);
561 MSG_create_environment(file);
562 smx_host_t *hosts = SIMIX_host_get_table();
564 for (i = 0; i < SIMIX_host_get_number(); i++) {
565 DEBUG1("We have an host %s", SIMIX_host_get_name(hosts[i]));
571 static int debug(lua_State * L)
573 const char *str = luaL_checkstring(L, 1);
578 static int info(lua_State * L)
580 const char *str = luaL_checkstring(L, 1);
585 static int run(lua_State * L)
591 static int clean(lua_State * L)
598 * Bypass XML Parser (lua console)
602 * Register platform for MSG
604 static int msg_register_platform(lua_State * L)
606 /* Tell Simgrid we dont wanna use its parser */
607 surf_parse = console_parse_platform;
608 MSG_create_environment(NULL);
613 * Register platform for Simdag
616 static int sd_register_platform(lua_State * L)
618 surf_parse = console_parse_platform_wsL07;
619 SD_create_environment(NULL);
624 * Register platform for gras
626 static int gras_register_platform(lua_State * L)
628 /* Tell Simgrid we dont wanna use surf parser */
629 surf_parse = console_parse_platform;
630 gras_create_environment(NULL);
635 * Register applicaiton for MSG
637 static int msg_register_application(lua_State * L)
639 MSG_function_register_default(run_lua_code);
640 surf_parse = console_parse_application;
641 MSG_launch_application(NULL);
646 * Register application for gras
648 static int gras_register_application(lua_State * L)
650 gras_function_register_default(run_lua_code);
651 surf_parse = console_parse_application;
652 gras_launch_application(NULL);
656 static const luaL_Reg simgrid_funcs[] = {
657 {"create_environment", create_environment},
658 {"launch_application", launch_application},
664 {"platform", create_environment},
665 {"application", launch_application},
666 /* methods to bypass XML parser */
667 {"msg_register_platform", msg_register_platform},
668 {"sd_register_platform", sd_register_platform},
669 {"msg_register_application", msg_register_application},
670 {"gras_register_platform", gras_register_platform},
671 {"gras_register_application", gras_register_application},
672 /* gras sub generator method */
673 {"gras_set_process_function", gras_add_process_function},
674 {"gras_generate", gras_generate},
678 /* ********************************************************************************* */
679 /* module management functions */
680 /* ********************************************************************************* */
682 extern const char *xbt_ctx_factory_to_use; /*Hack: let msg load directly the right factory */
684 #define LUA_MAX_ARGS_COUNT 10 /* maximum amount of arguments we can get from lua on command line */
686 int luaopen_simgrid(lua_State * L); // Fuck gcc: we don't need that prototype
687 int luaopen_simgrid(lua_State * L)
690 //xbt_ctx_factory_to_use = "lua";
691 char **argv = malloc(sizeof(char *) * LUA_MAX_ARGS_COUNT);
693 argv[0] = (char *) "/usr/bin/lua"; /* Lie on the argv[0] so that the stack dumping facilities find the right binary. FIXME: what if lua is not in that location? */
694 /* Get the command line arguments from the lua interpreter */
695 lua_getglobal(L, "arg");
696 /* if arg is a null value, it means we use lua only as a script to init platform
697 * else it should be a table and then take arg in consideration
699 if (lua_istable(L, -1)) {
703 lua_pushinteger(L, argc - 2);
705 if (lua_isnil(L, -1)) {
708 xbt_assert1(lua_isstring(L, -1),
709 "argv[%d] got from lua is no string", argc - 1);
710 xbt_assert2(argc < LUA_MAX_ARGS_COUNT,
711 "Too many arguments, please increase LUA_MAX_ARGS_COUNT in %s before recompiling SimGrid if you insist on having more than %d args on command line",
712 __FILE__, LUA_MAX_ARGS_COUNT - 1);
713 argv[argc - 1] = (char *) luaL_checkstring(L, -1);
715 DEBUG1("Got command line argument %s from lua", argv[argc - 1]);
720 /* Initialize the MSG core */
721 MSG_global_init(&argc, argv);
722 DEBUG1("Still %d arguments on command line", argc); // FIXME: update the lua's arg table to reflect the changes from SimGrid
724 /* register the core C functions to lua */
725 luaL_register(L, "simgrid", simgrid_funcs);
726 /* register the task methods to lua */
727 luaL_openlib(L, TASK_MODULE_NAME, Task_methods, 0); //create methods table,add it to the globals
728 luaL_newmetatable(L, TASK_MODULE_NAME); //create metatable for Task,add it to the Lua registry
729 luaL_openlib(L, 0, Task_meta, 0); // fill metatable
730 lua_pushliteral(L, "__index");
731 lua_pushvalue(L, -3); //dup methods table
732 lua_rawset(L, -3); //matatable.__index = methods
733 lua_pushliteral(L, "__metatable");
734 lua_pushvalue(L, -3); //dup methods table
735 lua_rawset(L, -3); //hide metatable:metatable.__metatable = methods
736 lua_pop(L, 1); //drop metatable
738 /* register the hosts methods to lua */
739 luaL_openlib(L, HOST_MODULE_NAME, Host_methods, 0);
740 luaL_newmetatable(L, HOST_MODULE_NAME);
741 luaL_openlib(L, 0, Host_meta, 0);
742 lua_pushliteral(L, "__index");
743 lua_pushvalue(L, -3);
745 lua_pushliteral(L, "__metatable");
746 lua_pushvalue(L, -3);
750 /* register the links methods to lua */
751 luaL_openlib(L, AS_MODULE_NAME, AS_methods, 0);
752 luaL_newmetatable(L, AS_MODULE_NAME);
755 /* register the links methods to lua */
756 luaL_openlib(L, LINK_MODULE_NAME, Link_methods, 0);
757 luaL_newmetatable(L, LINK_MODULE_NAME);
760 /*register the routes methods to lua */
761 luaL_openlib(L, ROUTE_MODULE_NAME, Route_methods, 0);
762 luaL_newmetatable(L, ROUTE_MODULE_NAME);
765 /*register the Tracing functions to lua */
766 luaL_openlib(L, TRACE_MODULE_NAME, Trace_methods, 0);
767 luaL_newmetatable(L, TRACE_MODULE_NAME);
770 /* Keep the context mechanism informed of our lua world today */
771 simgrid_lua_state = L;