PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/liquidwar6/src/lib/pil/pil-compute.c

#
C | 241 lines | 172 code | 14 blank | 55 comment | 28 complexity | f1ac8fe48ec225ae35fc13ab815c8102 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-4.0
  1. /*
  2. Liquid War 6 is a unique multiplayer wargame.
  3. Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Christian Mauduit <ufoot@ufoot.org>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. Liquid War 6 homepage : http://www.gnu.org/software/liquidwar6/
  15. Contact author : ufoot@ufoot.org
  16. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif // HAVE_CONFIG_H
  20. #include "pil.h"
  21. #include "pil-internal.h"
  22. void
  23. _lw6pil_compute_thread_func (lw6sys_context_t * sys_context, lw6pil_worker_t * worker)
  24. {
  25. lw6pil_command_t *command = NULL;
  26. lw6sys_list_t *commands = NULL;
  27. u_int32_t team_mask_even = 0;
  28. u_int32_t team_mask_odd = 0;
  29. _lw6pil_spread_data_t spread_data;
  30. lw6sys_thread_handler_t *spread_thread;
  31. int64_t timestamp = 0LL;
  32. lw6pil_pilot_t *old_worker_dump_pilot_ptr = NULL;
  33. u_int32_t old_worker_dump_pilot_id = 0;
  34. int yield_limit = 0;
  35. int yield_period = 1;
  36. memset (&spread_data, 0, sizeof (_lw6pil_spread_data_t));
  37. LW6SYS_MUTEX_LOCK (sys_context, worker->global_mutex);
  38. yield_limit = lw6sys_imax (1, (worker->game_state->game_struct->rules.rounds_per_sec * _LW6PIL_YIELD_LIMIT_MSEC) / 1000);
  39. yield_period = lw6sys_imax (1, (worker->game_state->game_struct->rules.rounds_per_sec * _LW6PIL_YIELD_PERIOD_MSEC) / 1000);
  40. LW6SYS_MUTEX_UNLOCK (sys_context, worker->global_mutex);
  41. while (worker->run)
  42. {
  43. commands = NULL;
  44. command = NULL;
  45. if (worker->verified)
  46. {
  47. timestamp = lw6sys_get_timestamp (sys_context);
  48. }
  49. commands = lw6sys_list_r_transfer_to (sys_context, worker->commands);
  50. if (commands)
  51. {
  52. lw6sys_sort (sys_context, &commands, _lw6pil_command_sort_callback, NULL);
  53. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker global compute begin %d"), worker->current_round);
  54. LW6SYS_MUTEX_LOCK (sys_context, worker->global_mutex);
  55. while (worker->run && commands && (command = lw6sys_list_pop_front (sys_context, &commands)) != NULL)
  56. {
  57. command->round = lw6sys_imax (command->round, worker->current_round);
  58. while (worker->run && worker->current_round < command->round)
  59. {
  60. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker compute begin %d"), worker->current_round);
  61. LW6SYS_MUTEX_LOCK (sys_context, worker->compute_mutex);
  62. lw6ker_team_mask_best (sys_context, &team_mask_even, &team_mask_odd, worker->game_state);
  63. worker->target_round = command->round;
  64. if (worker->game_state->game_struct->rules.spread_thread)
  65. {
  66. // even compute
  67. spread_data.game_state = worker->game_state;
  68. spread_data.team_mask = team_mask_odd;
  69. spread_thread =
  70. lw6sys_thread_create (sys_context, (lw6sys_thread_callback_func_t) _lw6pil_spread_thread_func, NULL, (void *) &spread_data);
  71. lw6ker_game_state_do_move (sys_context, worker->game_state, team_mask_even);
  72. if (spread_thread)
  73. {
  74. lw6sys_thread_join (sys_context, spread_thread);
  75. }
  76. else
  77. {
  78. lw6sys_log (sys_context, LW6SYS_LOG_WARNING, _x_ ("unable to spawn spread_thread"));
  79. _lw6pil_spread_thread_func (sys_context, &spread_data);
  80. }
  81. // odd compute
  82. spread_data.game_state = worker->game_state;
  83. spread_data.team_mask = team_mask_even;
  84. spread_thread =
  85. lw6sys_thread_create (sys_context, (lw6sys_thread_callback_func_t) _lw6pil_spread_thread_func, NULL, (void *) &spread_data);
  86. lw6ker_game_state_do_move (sys_context, worker->game_state, team_mask_odd);
  87. if (spread_thread)
  88. {
  89. lw6sys_thread_join (sys_context, spread_thread);
  90. }
  91. else
  92. {
  93. lw6sys_log (sys_context, LW6SYS_LOG_WARNING, _x_ ("unable to spawn spread_thread"));
  94. _lw6pil_spread_thread_func (sys_context, &spread_data);
  95. }
  96. lw6ker_game_state_finish_round (sys_context, worker->game_state);
  97. }
  98. else
  99. {
  100. lw6ker_game_state_do_round (sys_context, worker->game_state);
  101. }
  102. worker->current_round++;
  103. if (lw6ker_game_state_is_over (sys_context, worker->game_state))
  104. {
  105. worker->over = 1;
  106. }
  107. else
  108. {
  109. if (worker->current_round != lw6ker_game_state_get_rounds (sys_context, worker->game_state))
  110. {
  111. lw6sys_log (sys_context, LW6SYS_LOG_WARNING,
  112. _x_
  113. ("possible race condition, worker and game_state do not report the same round number (%d vs %d)"),
  114. worker->current_round, lw6ker_game_state_get_rounds (sys_context, worker->game_state));
  115. }
  116. }
  117. worker->computed_rounds++;
  118. LW6SYS_MUTEX_UNLOCK (sys_context, worker->compute_mutex);
  119. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker compute end %d"), worker->current_round);
  120. /*
  121. * https://savannah.gnu.org/bugs/index.php?41113
  122. * One needs to stop calculating like mad if one is way behind schedule
  123. * else control thread never gets its hands on this. In real games
  124. * this rarely happens if the computer is correctly calibrated
  125. * but during the bench we're actually targetting an infinite
  126. * (or, for that matter, it's pretty much the same, as great as possible)
  127. * number of rounds, so with lots of fast cores, the unlock/lock is done
  128. * too fast for the control thread to hope and get the lock.
  129. * Going idle() does fix the problem, there's no garantee (after all,
  130. * main thread could never be fast enough to catch up) but in practice
  131. * it does work.
  132. */
  133. if ((worker->target_round - worker->current_round > yield_limit) && (!(worker->computed_rounds % yield_period)))
  134. {
  135. lw6sys_log (sys_context, LW6SYS_LOG_INFO,
  136. _x_
  137. ("at round %d and targetting %d, yielding a timeslice every %d rounds"),
  138. worker->current_round, worker->target_round, yield_period);
  139. lw6sys_idle (sys_context);
  140. }
  141. }
  142. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker execute begin %d"), worker->current_round);
  143. LW6SYS_MUTEX_LOCK (sys_context, worker->compute_mutex);
  144. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker execute command %s"), command->text);
  145. if (worker->verified)
  146. {
  147. lw6pil_command_execute (sys_context, &(worker->dump), timestamp, worker->game_state, command);
  148. if (lw6pil_dump_exists (sys_context, &(worker->dump)) &&
  149. ((old_worker_dump_pilot_ptr != worker->dump.pilot) || (old_worker_dump_pilot_id != worker->dump.pilot->id)))
  150. {
  151. if (commands)
  152. {
  153. lw6sys_list_map (sys_context, commands, _lw6pil_compute_pump_command_callback, worker->dump.pilot);
  154. }
  155. }
  156. /*
  157. * It's important to keep a track of the previous dump,
  158. * to avoid putting messages twice in it. In practice it should
  159. * be rare. Note that we srt these old_worker values *after*
  160. * pumping the data if needed, this way if there's already a
  161. * dump from previous compute, data will be appended the right way.
  162. */
  163. old_worker_dump_pilot_ptr = worker->dump.pilot;
  164. if (old_worker_dump_pilot_ptr)
  165. {
  166. old_worker_dump_pilot_id = old_worker_dump_pilot_ptr->id;
  167. }
  168. }
  169. else
  170. {
  171. /*
  172. * Not in verified mode, we ignore all that dump stuff, if there's a
  173. * dump we ignore it, the cost of processing it is too expensive
  174. * compared to the gain it would introduce, we'll treat it when
  175. * it's verified, meanwhile, keep working on old map.
  176. */
  177. lw6pil_command_execute (sys_context, NULL, 0L, worker->game_state, command);
  178. }
  179. LW6SYS_MUTEX_UNLOCK (sys_context, worker->compute_mutex);
  180. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker execute end %d"), worker->current_round);
  181. lw6pil_command_free (sys_context, command);
  182. }
  183. LW6SYS_MUTEX_UNLOCK (sys_context, worker->global_mutex);
  184. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker global compute end %d"), worker->current_round);
  185. if (commands)
  186. {
  187. // commands could be NULL if stopped by worker->run==0
  188. lw6sys_list_free (sys_context, commands);
  189. }
  190. }
  191. else
  192. {
  193. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker idle"));
  194. lw6sys_idle (sys_context);
  195. }
  196. }
  197. }
  198. void
  199. _lw6pil_compute_thread_join (lw6sys_context_t * sys_context, lw6pil_worker_t * worker)
  200. {
  201. lw6sys_log (sys_context, LW6SYS_LOG_DEBUG, _x_ ("worker compute join"));
  202. }
  203. void
  204. _lw6pil_compute_pump_command_callback (lw6sys_context_t * sys_context, void *func_data, void *data)
  205. {
  206. _lw6pil_pilot_t *pilot = (_lw6pil_pilot_t *) func_data;
  207. lw6pil_command_t *command = (lw6pil_command_t *) data;
  208. if (pilot && command && command->text)
  209. {
  210. /*
  211. * Log this because this is probably very error prone,
  212. * recopy of pending messages is a tricky stuff, and does not
  213. * happen often, so we log it.
  214. */
  215. lw6sys_log (sys_context, LW6SYS_LOG_INFO, _x_ ("copying command \"%s\" into other pilot (dump)"), command->text);
  216. _lw6pil_pilot_send_command (sys_context, pilot, command->text, 1);
  217. }
  218. else
  219. {
  220. lw6sys_log (sys_context, LW6SYS_LOG_WARNING, _x_ ("bad parameters for pump command callback"));
  221. }
  222. }