File: SyncDebugger.h

package info (click to toggle)
spring 0.81.2.1%2Bdfsg1-6
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 28,496 kB
  • ctags: 37,096
  • sloc: cpp: 238,659; ansic: 13,784; java: 12,175; awk: 3,428; python: 1,159; xml: 738; perl: 405; sh: 297; makefile: 267; pascal: 228; objc: 192
file content (146 lines) | stat: -rw-r--r-- 4,749 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* Author: Tobi Vollebregt */

#ifndef SYNCDEBUGGER_H
#define SYNCDEBUGGER_H

#ifdef SYNCDEBUG

#include <assert.h>
#include <deque>
#include <vector>


/**
 * @brief sync debugger class
 *
 * The sync debugger keeps track of the results of the last assignments of
 * synced variables, and, if compiled with HAVE_BACKTRACE, it keeps a backtrace
 * for every assignment. This allows communication between client and server
 * to figure out which exact assignment (including backtrace) was the first
 * assignment to differ between client and server.
 */
class CSyncDebugger {

	public:

		static CSyncDebugger* GetInstance();

	private:

		enum {
			MAX_STACK = 5,       ///< Maximum number of stackframes per HistItemWithBacktrace.
			BLOCK_SIZE = 2048,   ///< Number of \p HistItem per block history.
			HISTORY_SIZE = 2048, ///< Number of blocks of the entire history.
		};

		/**
		 * @brief a clientside history item representing one assignment
		 *
		 * One clientside item in the history (without backtrace) is
		 * represented by this structure.
		 */
		struct HistItem {
			unsigned chk; ///< Checksum (XOR of 32 bit dwords of the data).
			unsigned data; ///< First four bytes of data
		};

		/**
		 * @brief a serverside history item representing one assignment
		 *
		 * One serverside item in the history (with backtrace) is represented
		 * by this structure.
		 */
		struct HistItemWithBacktrace: public HistItem {
			const char* op;      ///< Pointer to short static string giving operator type (e.g. "+=").
			unsigned frameNum;   ///< gs->frameNum at the time this entry was committed.
			unsigned bt_size;    ///< Number of entries in the stacktrace.
			void* bt[MAX_STACK]; ///< The stacktrace (frame pointers).
		};

	private:

		// client thread

		/**
		 * @brief the history on clients
		 *
		 * This points to the assignment history that doesn't have backtraces.
		 * It is used on platforms which don't have a backtrace() function
		 * (Windows) and on game clients. The game host uses historybt instead.
		 *
		 * Results of the last HISTORY_SIZE * BLOCK_SIZE = 2048 * 2048 = 4194304
		 * assignments to synced variables are stored in it.
		 *
		 * The size of the array is HISTORY_SIZE * BLOCK_SIZE * sizeof(HistItem),
		 * that is 2048*2048*4 = 16 megabytes.
		 */
		HistItem* history;

		/**
		 * @brief the history on the host
		 *
		 * This points to the assignment history that does have backtraces.
		 * It is used when running as server on platforms that have a
		 * backtrace() function. Game clients use the history array instead.
		 *
		 * Results of the last 4194304 assignments to synced variables are
		 * stored in it, with a backtrace attached to each of these results.
		 *
		 * This makes the size of the array HISTORY_SIZE * BLOCK_SIZE *
		 * sizeof(HistItemWithBacktrace), that is
		 * 2048*2048*(8+(MAX_STACK+1)*sizeof(void*)) = 128 megabytes on 32 bit
		 * systems and 224 megabytes on 64 bit systems.
		 */
		HistItemWithBacktrace* historybt;

		unsigned historyIndex;         ///< Where are we in the history buffer?
		volatile bool disable_history; ///< Volatile because it is read by server thread and written by client thread.
		bool may_enable_history;       ///< Is it safe already to set disable_history = false?
		boost::uint64_t flop;          ///< Current (local) operation number.

		// server thread

		struct PlayerStruct
		{
			std::vector<unsigned> checksumResponses;
			boost::uint64_t remoteFlop;
			std::vector<unsigned> remoteHistory;
		};
		typedef std::vector<PlayerStruct> playerVec;
		playerVec players;
		std::deque<unsigned> requestedBlocks;        ///< We are processing these blocks.
		std::deque<unsigned> pendingBlocksToRequest; ///< We still need to receive these blocks (slowly emptied).
		bool waitingForBlockResponse;                ///< Are we still waiting for a block response?

	private:

		// don't construct or copy
		CSyncDebugger();
		CSyncDebugger(const CSyncDebugger&);
		CSyncDebugger& operator=(const CSyncDebugger&);
		~CSyncDebugger();

		void Backtrace(int index, const char* prefix) const;
		unsigned GetBacktraceChecksum(int index) const;
		void ClientSendChecksumResponse();
		void ServerQueueBlockRequests();
		void ClientSendBlockResponse(int block);
		void ServerReceivedBlockResponses();
		void ServerDumpStack();
		void Sync(void* p, unsigned size, const char* op);

	public:

		void Initialize(bool useBacktrace, unsigned numPlayers);
		void ServerTriggerSyncErrorHandling(int serverframenum);
		bool ServerReceived(const unsigned char* inbuf);
		void ServerHandlePendingBlockRequests();
		bool ClientReceived(const unsigned char* inbuf);
		void Reset();

		friend class CSyncedPrimitiveBase;
};

#endif // SYNCDEBUG

#endif // SYNCDEBUGGER_H