compareDAGmapping.cpp 11.7 KB
Newer Older
1 2 3 4 5 6 7

// Keep in private GIT
#include <iostream>
#include <fstream>
#include <vector>
#include <regex>
#include <thread>
8 9
#include <deque>
#include <unordered_set>
10
#include <unordered_map>
11
#include <omp.h>
12 13
using namespace std;

14 15 16 17
#include "Utils/FGlobal.hpp"
#include "Utils/FMath.hpp"
#include "Utils/FParameters.hpp"
#include "Utils/FParameterNames.hpp"
18 19 20 21 22 23 24 25 26
enum TaskType {P2M = 0, M2M, M2L, M2L_OUT, L2L, L2P, P2P, P2P_OUT};
string taskNames[] = {"P2M", "M2M", "M2L", "M2L_out", "L2L", "L2P", "P2P", "P2P_out"};
struct Task
{
	TaskType type;
	long long int uniqueId;
	vector<long long int> id;
	int mpiNode;
	int level;
27
	double perf;
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	bool operator==(const Task & other) const
	{
		if(type != other.type || id.size() != other.id.size())
			return false;
		for(size_t i = 0; i < id.size(); ++i)
			if(id[i] != other.id[i])
				return false;
		return true;
	}
	bool operator!=(const Task & other) const
	{
		return !((*this)==other);
	}
	void print(void)
	{
		cout << taskNames[type];
		for(size_t i = 0; i < id.size(); ++i)
			cout << ", " << id[i];
46
		cout << "(mpi " << mpiNode << ")";
47 48 49 50 51 52 53 54 55 56 57 58 59
		cout << endl;
	}
};
//Spécialisation de hash pour le type Task
namespace std {
  template <> struct hash<Task>
  {
    size_t operator()(const Task & x) const
    {
		return x.uniqueId;
    }
  };
}
60 61
struct DagData
{
62
	unordered_set<Task> allTask;
63
	unordered_map<long long int, double> performence;
64
	int treeHeight;
65
};
66 67

bool parseLine(DagData & dagData, deque<string> & lineElements)
68
{
69 70 71 72 73 74 75
	if(lineElements.size() < 1)
		return false;
	Task task;
	if(lineElements.size() >= 14 && lineElements[0] == "P2P_out")
	{
		task.type = P2P_OUT;
		task.uniqueId = stoll(lineElements[1]);
76
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
77 78 79 80 81 82
		task.id.resize(4);
		task.id[0] = stoll(lineElements[9]);
		task.id[1] = stoll(lineElements[10]);
		task.id[2] = stoll(lineElements[11]);
		task.id[3] = stoll(lineElements[12]);
		task.mpiNode = stoi(lineElements[13]);
83
		task.level = dagData.treeHeight - 1;
84 85 86 87 88 89
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 10 && lineElements[0] == "P2P")
	{
		task.type = P2P;
		task.uniqueId = stoll(lineElements[1]);
90
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
91 92 93 94 95 96
		task.id.resize(4);
		task.id[0] = stoll(lineElements[5]);
		task.id[1] = stoll(lineElements[6]);
		task.id[2] = stoll(lineElements[7]);
		task.id[3] = stoll(lineElements[8]);
		task.mpiNode = stoi(lineElements[9]);
97
		task.level = dagData.treeHeight - 1;
98 99 100 101 102 103
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 10 && lineElements[0] == "M2L" )
	{
		task.type = M2L;
		task.uniqueId = stoll(lineElements[1]);
104
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
105 106 107 108 109 110 111
		task.id.resize(5);
		task.id[0] = stoll(lineElements[2]);
		task.id[1] = stoll(lineElements[5]);
		task.id[2] = stoll(lineElements[6]);
		task.id[3] = stoll(lineElements[7]);
		task.id[4] = stoll(lineElements[8]);
		task.mpiNode = stoi(lineElements[9]);
112
		task.level = (int)task.id[0];
113 114 115 116 117 118
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 13 && lineElements[0] == "M2L_out")
	{
		task.type = M2L_OUT;
		task.uniqueId = stoll(lineElements[1]);
119
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
120 121 122 123 124 125 126
		task.id.resize(5);
		task.id[0] = stoll(lineElements[2]);
		task.id[1] = stoll(lineElements[8]);
		task.id[2] = stoll(lineElements[9]);
		task.id[3] = stoll(lineElements[10]);
		task.id[4] = stoll(lineElements[11]);
		task.mpiNode = stoi(lineElements[12]);
127
		task.level = (int)task.id[0];
128 129 130 131 132 133
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 13 && lineElements[0] == "M2M")
	{
		task.type = M2M;
		task.uniqueId = stoll(lineElements[1]);
134
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
135 136 137 138 139 140 141
		task.id.resize(5);
		task.id[0] = stoll(lineElements[2]);
		task.id[1] = stoll(lineElements[8]);
		task.id[2] = stoll(lineElements[9]);
		task.id[3] = stoll(lineElements[10]);
		task.id[4] = stoll(lineElements[11]);
		task.mpiNode = stoi(lineElements[12]);
142
		task.level = (int)task.id[0];
143 144 145 146 147 148
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 13 && lineElements[0] == "L2L")
	{
		task.type = L2L;
		task.uniqueId = stoll(lineElements[1]);
149
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
150 151 152 153 154 155 156
		task.id.resize(5);
		task.id[0] = stoll(lineElements[2]);
		task.id[1] = stoll(lineElements[8]);
		task.id[2] = stoll(lineElements[9]);
		task.id[3] = stoll(lineElements[10]);
		task.id[4] = stoll(lineElements[11]);
		task.mpiNode = stoi(lineElements[12]);
157
		task.level = (int)task.id[0];
158 159 160 161 162 163
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 8 && lineElements[0] == "L2P")
	{
		task.type = L2P;
		task.uniqueId = stoll(lineElements[1]);
164
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
165 166 167 168
		task.id.resize(2);
		task.id[0] = stoll(lineElements[5]);
		task.id[1] = stoll(lineElements[6]);
		task.mpiNode = stoi(lineElements[7]);
169
		task.level = dagData.treeHeight - 1;
170 171 172 173 174 175
		dagData.allTask.insert(task);
	}
	else if(lineElements.size() >= 8 && lineElements[0] == "P2M")
	{
		task.type = L2P;
		task.uniqueId = stoll(lineElements[1]);
176
		task.perf = dagData.performence.count(task.uniqueId) == 1 ? dagData.performence[task.uniqueId] : 0.0;
177 178 179 180
		task.id.resize(2);
		task.id[0] = stoll(lineElements[5]);
		task.id[1] = stoll(lineElements[6]);
		task.mpiNode = stoi(lineElements[7]);
181
		task.level = 0;
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
		dagData.allTask.insert(task);
	}
	else
	{
		cout << "No match for " << lineElements[0] << " - " << lineElements.size() << endl;
		return false;
	}
	return true;
}
void split(string& line, string const& delim, deque<string> &result)
{
	size_t prevPos = 0;
	size_t pos = 0;
	while((pos = line.find(delim, prevPos)) != string::npos)
	{
		result.push_back(line.substr(prevPos, pos-prevPos));
		prevPos = pos+delim.size();
199
	}
200 201
	if(prevPos < line.size())
		result.push_back(line.substr(prevPos));
202 203 204 205 206 207 208 209 210 211 212
}
bool fillDagData(const char* const filename, DagData & dagData)
{
	std::ifstream fichier(filename, ios::in);  // on ouvre le fichier en lecture

	if(!fichier)  // si l'ouverture a réussi
	{       
		cerr << "Couldn't open " << filename << endl;
		return false;
	}
	string line;
213 214
	string delim(", ");
	deque<string> splitLine;
215 216 217
	while(!fichier.eof())
	{
		getline(fichier, line);
218 219 220
		splitLine.clear();
		split(line, delim, splitLine);
		parseLine(dagData, splitLine);
221 222 223 224
	}
	fichier.close();  // on ferme le fichier
	return true;
}
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
bool getTaskPerf(string line, double &perf)
{
	perf = stod(line);
	return true;
}
bool getTaskId(string line, long long int & taskId)
{
	size_t pos = line.rfind('_');
	if(pos == string::npos)
		return false;
	taskId = stoll(line.substr(pos));
	return true;
}
void fillPerformanceData(const char* const filename, DagData & dagData)
{
	std::ifstream fichier(filename, ios::in);  // on ouvre le fichier en lecture

	if(!fichier)  // si l'ouverture a réussi
		cerr << "Couldn't open " << filename << endl;

	string line;
	string delim(", ");
	deque<string> splitLine;
	bool getPerf = false;
	long long int taskId;
	double perf;
	while(!fichier.eof())
	{
		getline(fichier, line);
		if(line.size() > 0 && line[0] == 'N')
		{
			if(getTaskId(line.substr(3), taskId))
				getPerf = true;
		}
		else if(getPerf && line.size() > 0 && line[0] == 'S')
		{
			if(getTaskPerf(line.substr(3), perf))
			{
				getPerf = false;;
				dagData.performence[taskId] = perf;
			}
		}
		splitLine.clear();
		split(line, delim, splitLine);
		parseLine(dagData, splitLine);
	}
	fichier.close();  // on ferme le fichier
}
273
void compareDag(DagData const& dag1, DagData const& dag2, int const treeHeight)
274
{
275
	#pragma omp parallel
276
	{
277
		#pragma omp single nowait
278
		{
279 280 281 282
			long long int notFoundCount[omp_get_num_threads()][treeHeight];
			long long int differenceMapping[omp_get_num_threads()][treeHeight];
			long long int taskCount[omp_get_num_threads()][treeHeight];
			for(int i = 0; i < omp_get_num_threads(); ++i)
283
			{
284 285 286 287 288 289 290 291 292 293 294 295 296 297
				for(int j = 0; j < treeHeight; ++j)
				{
					notFoundCount[i][j] = 0;
					taskCount[i][j] = 0;
					differenceMapping[i][j] = 0;
				}
			}
			for(Task task : dag1.allTask)
			{
				#pragma omp task default(shared) firstprivate(task)
				{
					bool found = false;
					Task sameTask[2];
					int sameTaskId = 0;
298
					//Count task per level
299 300
					if(task.level < treeHeight)
						++taskCount[omp_get_thread_num()][task.level];
301 302
					//Look into the second dag to find task in it
					//We look for two task because it may be symetrized
303 304 305 306 307 308 309 310 311 312
					for(auto it = dag2.allTask.begin(); it != dag2.allTask.end(); ++it)
					{
						if(task == *it)
						{
							sameTask[sameTaskId++] = *it;
							found = true;
							if(sameTaskId == 2)
								break;
						}
					}
313
					//If the task it not found, print it and count it
314 315
					if(found == false)
					{
316 317
						#pragma omp critical
						task.print();
318 319 320
						if(task.level < treeHeight)
							++notFoundCount[omp_get_thread_num()][task.level];
					}
321
					else //else check the mapping
322 323 324 325 326
					{
						bool sameNode = false;
						for(int i = 0; i < sameTaskId; ++i)
							if(sameTask[i].mpiNode == task.mpiNode)
								sameNode = true;
327
						//The tasks are not mapped on the same node	
328 329 330 331 332 333 334
						if(!sameNode)
							if(task.level < treeHeight)
								++differenceMapping[omp_get_thread_num()][task.level];
					}
				}
			}
			#pragma omp taskwait
335
			//Sum results by level and print it
336 337 338 339 340 341 342 343 344 345 346 347
			for(int i = 0; i < treeHeight; ++i)
			{
				long long int sum = 0;
				long long int sumDiffMapping = 0;
				long long int sumTaskCount = 0;
				for(int j = 0; j < omp_get_num_threads(); ++j)
					if(taskCount[j][i] > 0)
					{
						sum += notFoundCount[j][i];
						sumDiffMapping += differenceMapping[j][i];
						sumTaskCount += taskCount[j][i];
					}
348
				//Print only if there is error repported on the level
349 350
				if(sum > 0 || sumDiffMapping > 0)
					std::cout << "Diff lvl " << i << " -> " << sum << " (Mapping error : " << sumDiffMapping << "/" << sumTaskCount << ")" << std::endl;
351 352 353
			}
		}
	}
354
}
355 356 357 358 359 360 361 362 363 364
int main(int argc, char* argv[])
{
    const FParameterNames ExplicitTrace {
        {"-E"},
        "Simgrid trace from explicit mpi"
    };
	const FParameterNames ImplicitTrace {
		{"-I"} ,
		"Simgrid trace from implicit mpi"
	};
365 366
    const FParameterNames Explicit {
        {"-e"},
367
        "Simgrid trace from explicit mpi"
368 369 370
    };
	const FParameterNames Implicit {
		{"-i"} ,
371
		"Simgrid trace from implicit mpi"
372
	};
373 374 375 376
    const FParameterNames TreeHeight {
        {"-h"},
        "Height of the tree"
    };
377
    FHelpDescribeAndExit(argc, argv, "Compare DAG mapping", Explicit, Implicit, ExplicitTrace, ImplicitTrace, TreeHeight);
378 379

    // Get params
380 381
    const char* const explicitFilename = FParameters::getStr(argc,argv,Explicit.options, "scalfmm_explicit.out");
    const char* const implicitFilename = FParameters::getStr(argc,argv,Implicit.options, "scalfmm_implicit.out");
382
    const int treeHeight = FParameters::getValue(argc,argv,TreeHeight.options, 5);
383 384 385

	DagData implicitData, explicitData;
	bool implicitGood, explicitGood;
386
	//Read data from files and put it into the DAG data structure
387
	std::thread explicitThread([&](){
388
		explicitData.treeHeight = treeHeight;
389 390
		explicitGood = fillDagData(explicitFilename, explicitData);
		});
391
	std::thread implicitThread([&](){
392
		implicitData.treeHeight = treeHeight;
393 394 395
		implicitGood = fillDagData(implicitFilename, implicitData);
		});
	implicitThread.join();
396
	explicitThread.join();
397
	//If every thing went good, start comparing
398
	if(implicitGood && explicitGood)
399 400 401
	{
		cout << explicitData.allTask.size() << " tasks in explicit." << endl;
		cout << implicitData.allTask.size() << " tasks in implicit." << endl;
402
		//compareDag(implicitData, explicitData, treeHeight);
403
		compareDag(explicitData, implicitData, treeHeight);
404
	}
405 406
    return 0;
}