1 /* Copyright (c) 2008-2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include "mc_request.h"
10 #include "mc_safety.h"
11 #include "mc_private.h"
15 using simgrid::mc::remote;
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_request, mc,
20 "Logging specific to MC (request)");
22 static char *pointer_to_string(void *pointer);
23 static char *buff_size_to_string(size_t size);
26 smx_synchro_t MC_get_comm(smx_simcall_t r)
29 case SIMCALL_COMM_WAIT:
30 return simcall_comm_wait__get__comm(r);
31 case SIMCALL_COMM_TEST:
32 return simcall_comm_test__get__comm(r);
39 smx_rdv_t MC_get_rdv(smx_simcall_t r)
42 case SIMCALL_COMM_ISEND:
43 return simcall_comm_isend__get__rdv(r);
44 case SIMCALL_COMM_IRECV:
45 return simcall_comm_irecv__get__rdv(r);
53 int MC_request_depend_asymmetric(smx_simcall_t r1, smx_simcall_t r2)
55 if (r1->call == SIMCALL_COMM_ISEND && r2->call == SIMCALL_COMM_IRECV)
58 if (r1->call == SIMCALL_COMM_IRECV && r2->call == SIMCALL_COMM_ISEND)
61 // Those are internal requests, we do not need indirection
62 // because those objects are copies:
63 smx_synchro_t synchro1 = MC_get_comm(r1);
64 smx_synchro_t synchro2 = MC_get_comm(r2);
66 if ((r1->call == SIMCALL_COMM_ISEND || r1->call == SIMCALL_COMM_IRECV)
67 && r2->call == SIMCALL_COMM_WAIT) {
69 smx_rdv_t rdv = MC_get_rdv(r1);
71 if (rdv != synchro2->comm.rdv_cpy
72 && simcall_comm_wait__get__timeout(r2) <= 0)
75 if ((r1->issuer != synchro2->comm.src_proc)
76 && (r1->issuer != synchro2->comm.dst_proc)
77 && simcall_comm_wait__get__timeout(r2) <= 0)
80 if ((r1->call == SIMCALL_COMM_ISEND)
81 && (synchro2->comm.type == SIMIX_COMM_SEND)
82 && (synchro2->comm.src_buff !=
83 simcall_comm_isend__get__src_buff(r1))
84 && simcall_comm_wait__get__timeout(r2) <= 0)
87 if ((r1->call == SIMCALL_COMM_IRECV)
88 && (synchro2->comm.type == SIMIX_COMM_RECEIVE)
89 && (synchro2->comm.dst_buff != simcall_comm_irecv__get__dst_buff(r1))
90 && simcall_comm_wait__get__timeout(r2) <= 0)
94 /* FIXME: the following rule assumes that the result of the
95 * isend/irecv call is not stored in a buffer used in the
97 /*if( (r1->call == SIMCALL_COMM_ISEND || r1->call == SIMCALL_COMM_IRECV)
98 && r2->call == SIMCALL_COMM_TEST)
101 if (r1->call == SIMCALL_COMM_WAIT
102 && (r2->call == SIMCALL_COMM_WAIT || r2->call == SIMCALL_COMM_TEST)
103 && (synchro1->comm.src_proc == NULL || synchro1->comm.dst_proc == NULL))
106 if (r1->call == SIMCALL_COMM_TEST &&
107 (simcall_comm_test__get__comm(r1) == NULL
108 || synchro1->comm.src_buff == NULL
109 || synchro1->comm.dst_buff == NULL))
112 if (r1->call == SIMCALL_COMM_TEST && r2->call == SIMCALL_COMM_WAIT
113 && synchro1->comm.src_buff == synchro2->comm.src_buff
114 && synchro1->comm.dst_buff == synchro2->comm.dst_buff)
117 if (r1->call == SIMCALL_COMM_WAIT && r2->call == SIMCALL_COMM_TEST
118 && synchro1->comm.src_buff != NULL
119 && synchro1->comm.dst_buff != NULL
120 && synchro2->comm.src_buff != NULL
121 && synchro2->comm.dst_buff != NULL
122 && synchro1->comm.dst_buff != synchro2->comm.src_buff
123 && synchro1->comm.dst_buff != synchro2->comm.dst_buff
124 && synchro2->comm.dst_buff != synchro1->comm.src_buff)
130 // Those are MC_state_get_internal_request(state)
131 int MC_request_depend(smx_simcall_t r1, smx_simcall_t r2)
133 if (mc_reduce_kind == e_mc_reduce_none)
136 if (r1->issuer == r2->issuer)
139 /* Wait with timeout transitions are not considered by the independance theorem, thus we consider them as dependant with all other transitions */
140 if ((r1->call == SIMCALL_COMM_WAIT && simcall_comm_wait__get__timeout(r1) > 0)
141 || (r2->call == SIMCALL_COMM_WAIT
142 && simcall_comm_wait__get__timeout(r2) > 0))
145 if (r1->call != r2->call)
146 return MC_request_depend_asymmetric(r1, r2)
147 && MC_request_depend_asymmetric(r2, r1);
149 // Those are internal requests, we do not need indirection
150 // because those objects are copies:
151 smx_synchro_t synchro1 = MC_get_comm(r1);
152 smx_synchro_t synchro2 = MC_get_comm(r2);
155 case SIMCALL_COMM_ISEND:
156 return simcall_comm_isend__get__rdv(r1) == simcall_comm_isend__get__rdv(r2);
157 case SIMCALL_COMM_IRECV:
158 return simcall_comm_irecv__get__rdv(r1) == simcall_comm_irecv__get__rdv(r2);
159 case SIMCALL_COMM_WAIT:
160 if (synchro1->comm.src_buff == synchro2->comm.src_buff
161 && synchro1->comm.dst_buff == synchro2->comm.dst_buff)
163 else if (synchro1->comm.src_buff != NULL
164 && synchro1->comm.dst_buff != NULL
165 && synchro2->comm.src_buff != NULL
166 && synchro2->comm.dst_buff != NULL
167 && synchro1->comm.dst_buff != synchro2->comm.src_buff
168 && synchro1->comm.dst_buff != synchro2->comm.dst_buff
169 && synchro2->comm.dst_buff != synchro1->comm.src_buff)
178 static char *pointer_to_string(void *pointer)
181 if (XBT_LOG_ISENABLED(mc_request, xbt_log_priority_verbose))
182 return bprintf("%p", pointer);
184 return xbt_strdup("(verbose only)");
187 static char *buff_size_to_string(size_t buff_size)
190 if (XBT_LOG_ISENABLED(mc_request, xbt_log_priority_verbose))
191 return bprintf("%zu", buff_size);
193 return xbt_strdup("(verbose only)");
197 char *MC_request_to_string(smx_simcall_t req, int value, e_mc_request_type_t request_type)
199 bool use_remote_comm = true;
200 switch(request_type) {
201 case MC_REQUEST_SIMIX:
202 use_remote_comm = true;
204 case MC_REQUEST_EXECUTED:
205 case MC_REQUEST_INTERNAL:
206 use_remote_comm = false;
210 const char* type = NULL;
213 smx_process_t issuer = MC_smx_simcall_get_issuer(req);
217 case SIMCALL_COMM_ISEND: {
219 char* p = pointer_to_string(simcall_comm_isend__get__src_buff(req));
220 char* bs = buff_size_to_string(simcall_comm_isend__get__src_buff_size(req));
223 bprintf("src=(%lu)%s (%s), buff=%s, size=%s", issuer->pid,
224 MC_smx_process_get_host_name(issuer),
225 MC_smx_process_get_name(issuer),
229 bprintf("src=(%lu)%s, buff=%s, size=%s", issuer->pid,
230 MC_smx_process_get_name(issuer), p, bs);
236 case SIMCALL_COMM_IRECV: {
237 size_t* remote_size = simcall_comm_irecv__get__dst_buff_size(req);
239 // size_t size = size_pointer ? *size_pointer : 0;
242 mc_model_checker->process().read_bytes(&size, sizeof(size),
243 remote(remote_size));
246 char* p = pointer_to_string(simcall_comm_irecv__get__dst_buff(req));
247 char* bs = buff_size_to_string(size);
250 bprintf("dst=(%lu)%s (%s), buff=%s, size=%s", issuer->pid,
251 MC_smx_process_get_host_name(issuer),
252 MC_smx_process_get_name(issuer),
256 bprintf("dst=(%lu)%s, buff=%s, size=%s", issuer->pid,
257 MC_smx_process_get_name(issuer),
264 case SIMCALL_COMM_WAIT: {
265 smx_synchro_t remote_act = simcall_comm_wait__get__comm(req);
268 type = "WaitTimeout";
269 p = pointer_to_string(remote_act);
270 args = bprintf("comm=%s", p);
273 p = pointer_to_string(remote_act);
275 s_smx_synchro_t synchro;
277 if (use_remote_comm) {
278 mc_model_checker->process().read_bytes(&synchro,
279 sizeof(synchro), remote(remote_act));
284 smx_process_t src_proc = MC_smx_resolve_process(act->comm.src_proc);
285 smx_process_t dst_proc = MC_smx_resolve_process(act->comm.dst_proc);
286 args = bprintf("comm=%s [(%lu)%s (%s)-> (%lu)%s (%s)]", p,
287 src_proc ? src_proc->pid : 0,
288 src_proc ? MC_smx_process_get_host_name(src_proc) : "",
289 src_proc ? MC_smx_process_get_name(src_proc) : "",
290 dst_proc ? dst_proc->pid : 0,
291 dst_proc ? MC_smx_process_get_host_name(dst_proc) : "",
292 dst_proc ? MC_smx_process_get_name(dst_proc) : "");
298 case SIMCALL_COMM_TEST: {
299 smx_synchro_t remote_act = simcall_comm_test__get__comm(req);
300 s_smx_synchro_t synchro;
302 if (use_remote_comm) {
303 mc_model_checker->process().read_bytes(&synchro,
304 sizeof(synchro), remote(remote_act));
310 if (act->comm.src_proc == NULL || act->comm.dst_proc == NULL) {
312 p = pointer_to_string(remote_act);
313 args = bprintf("comm=%s", p);
316 p = pointer_to_string(remote_act);
318 smx_process_t src_proc = MC_smx_resolve_process(act->comm.src_proc);
319 smx_process_t dst_proc = MC_smx_resolve_process(act->comm.dst_proc);
320 args = bprintf("comm=%s [(%lu)%s (%s) -> (%lu)%s (%s)]", p,
322 MC_smx_process_get_name(src_proc),
323 MC_smx_process_get_host_name(src_proc),
325 MC_smx_process_get_name(dst_proc),
326 MC_smx_process_get_host_name(dst_proc));
332 case SIMCALL_COMM_WAITANY: {
335 mc_model_checker->process().read_bytes(
336 &comms, sizeof(comms), remote(simcall_comm_waitany__get__comms(req)));
337 if (!xbt_dynar_is_empty(&comms)) {
338 smx_synchro_t remote_sync;
339 read_element(mc_model_checker->process(),
340 &remote_sync, remote(simcall_comm_waitany__get__comms(req)), value,
341 sizeof(remote_sync));
342 char* p = pointer_to_string(remote_sync);
343 args = bprintf("comm=%s (%d of %lu)",
344 p, value + 1, xbt_dynar_length(&comms));
347 args = bprintf("comm at idx %d", value);
352 case SIMCALL_COMM_TESTANY:
354 type = "TestAny FALSE";
355 args = xbt_strdup("-");
359 bprintf("(%d of %zu)", value + 1,
360 read_length(mc_model_checker->process(),
361 simcall_comm_testany__get__comms(req)));
365 case SIMCALL_MUTEX_TRYLOCK:
366 case SIMCALL_MUTEX_LOCK: {
367 if (req->call == SIMCALL_MUTEX_LOCK)
370 type = "Mutex TRYLOCK";
373 mc_model_checker->process().read_bytes(&mutex, sizeof(mutex),
375 req->call == SIMCALL_MUTEX_LOCK
376 ? simcall_mutex_lock__get__mutex(req)
377 : simcall_mutex_trylock__get__mutex(req)
379 s_xbt_swag_t mutex_sleeping;
380 mc_model_checker->process().read_bytes(&mutex_sleeping, sizeof(mutex_sleeping),
381 remote(mutex.sleeping));
383 args = bprintf("locked = %d, owner = %d, sleeping = %d",
385 mutex.owner != NULL ? (int) MC_smx_resolve_process(mutex.owner)->pid : -1,
386 mutex_sleeping.count);
390 case SIMCALL_MC_SNAPSHOT:
391 type = "MC_SNAPSHOT";
395 case SIMCALL_MC_COMPARE_SNAPSHOTS:
396 type = "MC_COMPARE_SNAPSHOTS";
400 case SIMCALL_MC_RANDOM:
402 args = bprintf("%d", value);
412 bprintf("[(%lu)%s (%s)] %s(%s)", issuer->pid,
413 MC_smx_process_get_host_name(issuer),
414 MC_smx_process_get_name(issuer),
418 bprintf("[(%lu)%s (%s)] %s ", issuer->pid,
419 MC_smx_process_get_host_name(issuer),
420 MC_smx_process_get_name(issuer),
427 unsigned int MC_request_testany_fail(smx_simcall_t req)
429 // Remote xbt_dynar_foreach on simcall_comm_testany__get__comms(req).
433 mc_model_checker->process().read_bytes(
434 &comms, sizeof(comms), remote(simcall_comm_testany__get__comms(req)));
436 // Read ther dynar buffer:
437 size_t buffer_size = comms.elmsize * comms.used;
438 char buffer[buffer_size];
439 mc_model_checker->process().read_bytes(
440 buffer, buffer_size, remote(comms.data));
442 // Iterate over the elements:
443 assert(comms.elmsize == sizeof(smx_synchro_t));
445 for (cursor=0; cursor != comms.used; ++cursor) {
448 smx_synchro_t remote_action = NULL;
449 memcpy(&remote_action, buffer + comms.elmsize * cursor, sizeof(remote_action));
451 // Dereference the pointer:
452 s_smx_synchro_t action;
453 mc_model_checker->process().read_bytes(
454 &action, sizeof(action), remote(remote_action));
456 // Finally so something useful about it:
457 if (action.comm.src_proc && action.comm.dst_proc)
464 int MC_request_is_enabled_by_idx(smx_simcall_t req, unsigned int idx)
466 smx_synchro_t remote_act = NULL;
469 case SIMCALL_COMM_WAIT:
470 /* FIXME: check also that src and dst processes are not suspended */
471 remote_act = simcall_comm_wait__get__comm(req);
474 case SIMCALL_COMM_WAITANY: {
476 mc_model_checker->process(), &remote_act,
477 remote(simcall_comm_waitany__get__comms(req)),
478 idx, sizeof(remote_act));
482 case SIMCALL_COMM_TESTANY: {
484 mc_model_checker->process(), &remote_act,
485 remote(simcall_comm_testany__get__comms(req)),
486 idx, sizeof(remote_act));
494 s_smx_synchro_t synchro;
495 mc_model_checker->process().read_bytes(
496 &synchro, sizeof(synchro), remote(remote_act));
497 return synchro.comm.src_proc && synchro.comm.dst_proc;
500 int MC_process_is_enabled(smx_process_t process)
502 return MC_request_is_enabled(&process->simcall);
505 char *MC_request_get_dot_output(smx_simcall_t req, int value)
509 const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
512 case SIMCALL_COMM_ISEND:
515 bprintf("[(%lu)%s] iSend", issuer->pid,
516 MC_smx_process_get_host_name(issuer));
518 label = bprintf("[(%lu)] iSend", issuer->pid);
521 case SIMCALL_COMM_IRECV:
524 bprintf("[(%lu)%s] iRecv", issuer->pid,
525 MC_smx_process_get_host_name(issuer));
527 label = bprintf("[(%lu)] iRecv", issuer->pid);
530 case SIMCALL_COMM_WAIT: {
534 bprintf("[(%lu)%s] WaitTimeout", issuer->pid,
535 MC_smx_process_get_host_name(issuer));
537 label = bprintf("[(%lu)] WaitTimeout", issuer->pid);
539 smx_synchro_t remote_act = simcall_comm_wait__get__comm(req);
540 s_smx_synchro_t synchro;
541 mc_model_checker->process().read_bytes(&synchro,
542 sizeof(synchro), remote(remote_act));
544 smx_process_t src_proc = MC_smx_resolve_process(synchro.comm.src_proc);
545 smx_process_t dst_proc = MC_smx_resolve_process(synchro.comm.dst_proc);
548 bprintf("[(%lu)%s] Wait [(%lu)->(%lu)]", issuer->pid,
549 MC_smx_process_get_host_name(issuer),
550 src_proc ? src_proc->pid : 0,
551 dst_proc ? dst_proc->pid : 0);
554 bprintf("[(%lu)] Wait [(%lu)->(%lu)]", issuer->pid,
555 src_proc ? src_proc->pid : 0,
556 dst_proc ? dst_proc->pid : 0);
561 case SIMCALL_COMM_TEST: {
562 smx_synchro_t remote_act = simcall_comm_test__get__comm(req);
563 s_smx_synchro_t synchro;
564 mc_model_checker->process().read_bytes(&synchro,
565 sizeof(synchro), remote(remote_act));
566 if (synchro.comm.src_proc == NULL || synchro.comm.dst_proc == NULL) {
569 bprintf("[(%lu)%s] Test FALSE", issuer->pid,
570 MC_smx_process_get_host_name(issuer));
572 label = bprintf("[(%lu)] Test FALSE", issuer->pid);
576 bprintf("[(%lu)%s] Test TRUE", issuer->pid,
577 MC_smx_process_get_host_name(issuer));
579 label = bprintf("[(%lu)] Test TRUE", issuer->pid);
584 case SIMCALL_COMM_WAITANY: {
585 unsigned long comms_size = read_length(
586 mc_model_checker->process(), remote(simcall_comm_waitany__get__comms(req)));
589 bprintf("[(%lu)%s] WaitAny [%d of %lu]", issuer->pid,
590 MC_smx_process_get_host_name(issuer), value + 1,
594 bprintf("[(%lu)] WaitAny [%d of %lu]", issuer->pid, value + 1,
599 case SIMCALL_COMM_TESTANY:
603 bprintf("[(%lu)%s] TestAny FALSE", issuer->pid,
604 MC_smx_process_get_host_name(issuer));
606 label = bprintf("[(%lu)] TestAny FALSE", issuer->pid);
610 bprintf("[(%lu)%s] TestAny TRUE [%d of %lu]", issuer->pid,
611 MC_smx_process_get_host_name(issuer), value + 1,
612 xbt_dynar_length(simcall_comm_testany__get__comms(req)));
615 bprintf("[(%lu)] TestAny TRUE [%d of %lu]", issuer->pid,
617 xbt_dynar_length(simcall_comm_testany__get__comms(req)));
621 case SIMCALL_MUTEX_TRYLOCK:
622 label = bprintf("[(%lu)] Mutex TRYLOCK", issuer->pid);
625 case SIMCALL_MUTEX_LOCK:
626 label = bprintf("[(%lu)] Mutex LOCK", issuer->pid);
629 case SIMCALL_MC_RANDOM:
632 bprintf("[(%lu)%s] MC_RANDOM (%d)", issuer->pid,
633 MC_smx_process_get_host_name(issuer), value);
635 label = bprintf("[(%lu)] MC_RANDOM (%d)", issuer->pid, value);
638 case SIMCALL_MC_SNAPSHOT:
641 bprintf("[(%lu)%s] MC_SNAPSHOT", issuer->pid,
642 MC_smx_process_get_host_name(issuer));
644 label = bprintf("[(%lu)] MC_SNAPSHOT", issuer->pid);
647 case SIMCALL_MC_COMPARE_SNAPSHOTS:
650 bprintf("[(%lu)%s] MC_COMPARE_SNAPSHOTS", issuer->pid,
651 MC_smx_process_get_host_name(issuer));
653 label = bprintf("[(%lu)] MC_COMPARE_SNAPSHOTS", issuer->pid);
661 bprintf("label = \"%s\", color = %s, fontcolor = %s", label,
662 colors[issuer->pid - 1], colors[issuer->pid - 1]);