///////////////////////////////////////////////////////////////////////
////  Copyright 2022 by mars.                                        //
///////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "getopt.h"
#include "cbsl.h"

#define CBSL_ERROR_CHECK(X)  {if ((X) == cbsl_error) { fprintf(stderr, "error: %s\n", (#X)); }}

/*
fcn  ideal%     #items   #buckets  dup%  fl   add_usec  find_usec  del-all usec
---  ------ ---------- ---------- -----  -- ---------- ----------  ------------
OAT   89.1%     597731     524288    0%  ok     317292     179676         59726
FNV   88.6%     597731     262144    0%  ok     226650     220626         61619
JEN   87.8%     597731     524288    0%  ok     321989     175945         59956
BER   86.4%     597731     262144    0%  ok     198477     179332         60901
SAX   70.4%     597731     524288    0%  ok     270281     196427         64064
SFH   69.2%     597731     524288    0%  ok     289843     165105         61860
FNV1A_Pippip_Yurii 更快？？
*/

// 使用OAT hash算法，以获得最高性能
#include "uthash.h"
#undef HASH_FUNCTION
//#define HASH_FUNCTION HASH_OAT
#define HASH_FUNCTION(keyptr,keylen,hashv) (hashv) = FNV1A_Pippip_Yurii((UINT64 *)keyptr)

#define VERBOSE_MSG	0

#ifdef _WIN32
#define ZLIB_WINAPI
#endif

#include "common.h"

#ifdef _WIN64
#pragma comment(lib,"..\\zstd\\libzstd_static-win64.lib")
#elif  _WIN32
#pragma comment(lib,"..\\zstd\\libzstd_static-win32.lib")
#endif

/*
	构建一个用Hash表访问的Memory，以便能够紧凑存放稀疏、随机的Memory数据
*/

struct MemoryDataStruct
{
	UINT64 Address;			// 地址（默认是64位字地址）
	UINT64 Data;			// 数据（默认保存64位字数据）
	UT_hash_handle memory;	// makes this structure hashable
} *MemoryHash = NULL;

static void WriteMemoryHash(UINT64 Address, UINT64 WriteValue, UINT8 WriteSize);
static UINT64 ReadMemoryHash(UINT64 Address, UINT8 ReadSize);

#define MEMORY_TRACE_CHUNK	(1<<20)	// MemoryTrace结构，每次增长1M条记录
struct MemoryTraceStruct
{
	UINT8 Operation;
	UINT64 Address;
	UINT8 Size;
} *MemoryTrace;
UINT64 MemoryTraceCounter, MemoryTraceCapacity;

/*
*	统计计数器
*/
UINT64 GlobalMemoryModifyCounter;
UINT64 GlobalMemoryInstCounter;
UINT64 GlobalMemoryWriteCounter;
UINT64 GlobalCacheWriteHitCounter;
UINT64 GlobalMemoryReadCounter;
UINT64 GlobalCacheReadHitCounter;
UINT64 GlobalCacheModifyHitCounter;
UINT64 GlobalSimReadMemoryCounter;
UINT64 GlobalSimWriteMemoryCounter;

UINT64 GlobalCacheInstHitCounter;

#define CHUNK 16384

static void Trim(char* src)
{
	char* begin = src;
	char* end = src + strlen(src);

	if (begin == end) return;

	while (*begin == ' ' || *begin == '\t')
		++begin;
	while ((*end) == '\0' || *end == ' ' || *end == '\t' || *end == '\n' || *end == '\r')
		--end;

	if (begin > end) {
		*src = '\0';  return;
	}
	while (begin != end) {
		*src++ = *begin++;
	}

	*src++ = *end;
	*src = '\0';

	return;
}

typedef struct {
	const char* start;
	size_t len;
} token;

// https://stackoverflow.com/a/39286524
static char** split_space(const char* str, int* field_count)
{
	char** array;
	unsigned int start = 0, stop, toks = 0, t;
	token* tokens = malloc((strlen(str) + 1) * sizeof(token));
	for (stop = 0; str[stop]; stop++) {
		if (str[stop] == ' ' || str[stop] == '\t' || str[stop] == ',')
		{
			tokens[toks].start = str + start;
			tokens[toks].len = stop - start;
			toks++;
			start = stop + 1;
		}
	}
	/* Mop up the last token */
	tokens[toks].start = str + start;
	tokens[toks].len = stop - start;
	toks++;
	array = malloc(toks * sizeof(char*));
	for (t = 0; t < toks; t++) {
		/* Calloc makes it nul-terminated */
		char* token = calloc(tokens[t].len + 1, 1);
		memcpy(token, tokens[t].start, tokens[t].len);
		array[t] = token;
	}
	free(tokens);
	*field_count = toks;
	return array;
}

#define SR_A ((UINT64)1103515245)
#define SR_C ((UINT64)12345)
#define SR_M ((UINT64)1<<32)
UINT64 Xn;

static void SyncRand(UINT64 Seed)
{
	Xn = Seed;
}

static UINT8 GetRand8()
{
	Xn = ((SR_A * Xn + SR_C) % SR_M);
	return (UINT8)Xn;
}

static UINT16 GetRand16()
{
	Xn = ((SR_A * Xn + SR_C) % SR_M);
	return (UINT16)Xn;
}

static UINT32 GetRand32()
{
	Xn = ((SR_A * Xn + SR_C) % SR_M);
	return (UINT32)Xn;
}

static UINT64 GetRand64()
{
	UINT32 Hi, Lo;
	Hi = GetRand32();
	Lo = GetRand32();

	return ((UINT64)Hi << 32 | Lo);
}

//https://www.codeproject.com/articles/716530/fastest-hash-function-for-table-lookups-in-c
static inline UINT32 FNV1A_Pippip_Yurii(UINT64* Address)
{
	const UINT32 PRIME = 591798841; UINT32 hash32; UINT64 hash64 = 14695981039346656037ULL;
	hash64 = (hash64 ^ *Address) * PRIME;
	hash32 = (uint32_t)(hash64 ^ (hash64 >> 32));
	return hash32 ^ (hash32 >> 16);
}


static void InitMemoryHash()
{
}

static void FreeMemoryHash()
{
	struct MemoryDataStruct* p, * tmp;
	HASH_ITER(memory, MemoryHash, p, tmp)
	{
		HASH_DELETE(memory, MemoryHash, p);
		free(p);
	}
}

static void UpdateMemoryData(UINT64* Location, UINT8 Offset, UINT64 WriteValue, UINT8 WriteSize)
{
	UINT64 OriginValue;
	OriginValue = *Location;
	switch (WriteSize)
	{
	case 1:	// 1个字节
		Offset = Offset << 3;	// 从字节换算成位
		OriginValue = (OriginValue & ~((UINT64)0xFF << Offset)) | ((WriteValue & (UINT64)0xFF) << Offset);
		break;
	case 2:	// 2个字节
		Offset = Offset & 0xFE;	// 对齐到2字节边界
		Offset = Offset << 3;	// 从字节换算成位
		OriginValue = (OriginValue & ~((UINT64)0xFFFF << Offset)) | ((WriteValue & (UINT64)0xFFFF) << Offset);
		break;
	case 4:	// 4个字节
		Offset = Offset & 0xFC;	// 对齐到4字节边界
		Offset = Offset << 3;	// 从字节换算成位
		OriginValue = (OriginValue & ~((UINT64)0xFFFFFFFF << Offset)) | ((WriteValue & (UINT64)0xFFFFFFFF) << Offset);
		break;
	case 8:	// 8个字节
		OriginValue = WriteValue;
		break;
	}
	*Location = OriginValue;
}

static void WriteMemoryHash(UINT64 Address, UINT64 WriteValue, UINT8 WriteSize)
{
	UINT64 AlignAddress;
	UINT8 Offset;
	struct MemoryDataStruct* s;

	AlignAddress = Address & 0xFFFFFFFFFFFFFFF8;
	Offset = Address & 0x7;

	HASH_FIND(memory, MemoryHash, &AlignAddress, sizeof(AlignAddress), s);
	if (s == NULL)
	{
		// 没有在MemoryData中命中
		s = (struct MemoryDataStruct*)malloc(sizeof(struct MemoryDataStruct));
		s->Address = AlignAddress;
		s->Data = 0xDEADBEEFDEADC0DE;
		HASH_ADD(memory, MemoryHash, Address, sizeof(AlignAddress), s);
	}
	UpdateMemoryData(&(s->Data), Offset, WriteValue, WriteSize);
}

static UINT64 ReadMemoryHash(UINT64 Address, UINT8 ReadSize)
{
	UINT64 AlignAddress;
	UINT8 Offset;
	struct MemoryDataStruct* s;
	UINT64 OriginValue, ReadValue;

	AlignAddress = Address & 0xFFFFFFFFFFFFFFF8;
	Offset = Address & 0x7;

	HASH_FIND(memory, MemoryHash, &AlignAddress, sizeof(AlignAddress), s);
	if (s == NULL)
	{
		// 没有在MemoryData中命中，出错了！
		if (VERBOSE_MSG)
			printf("[%s] 试图从一个未初始化的内存读取数据Address=%016llX！\n", __func__, Address);
		OriginValue = 0xDEADBEEFDEADC0DE;
	}
	else
	{
		OriginValue = s->Data;
	}

	/*
	*  根据Offset和Size，对读出的数据进行修正，对齐到小端
	*/
	ReadValue = OriginValue;
	switch (ReadSize)
	{
	case 1:	// 1个字节
		Offset = Offset << 3;	// 从字节换算成位
		ReadValue = (OriginValue >> Offset) & 0xFF;
		break;
	case 2:	// 2个字节
		Offset = Offset & 0xFE;	// 对齐到2字节边界
		Offset = Offset << 3;	// 从字节换算成位
		ReadValue = (OriginValue >> Offset) & 0xFFFF;
		break;
	case 4:	// 4个字节
		Offset = Offset & 0xFC;	// 对齐到4字节边界
		Offset = Offset << 3;	// 从字节换算成位
		ReadValue = (OriginValue >> Offset) & 0xFFFFFFFF;
		break;
	case 8:	// 8个字节
		ReadValue = OriginValue;
		break;

	}
	return ReadValue;
}

UINT64 ReadMemory(UINT64 Address)
{
	GlobalSimReadMemoryCounter++;
	return ReadMemoryHash(Address, 8);
}

void WriteMemory(UINT64 Address, UINT64 WriteData)
{
	GlobalSimWriteMemoryCounter++;
	WriteMemoryHash(Address, WriteData, 8);
}

static void MemoryTraceStat()
{
	UINT64 i;

	GlobalMemoryInstCounter = 0;
	GlobalMemoryReadCounter = 0;
	GlobalMemoryWriteCounter = 0;
	GlobalMemoryModifyCounter = 0;

	for (i = 0; i < MemoryTraceCounter; i++)
	{
		if (MemoryTrace[i].Operation == 'I')
			GlobalMemoryInstCounter++;
		else if (MemoryTrace[i].Operation == 'L')
			GlobalMemoryReadCounter++;
		else if (MemoryTrace[i].Operation == 'S')
			GlobalMemoryWriteCounter++;
		else if (MemoryTrace[i].Operation == 'M')
			GlobalMemoryModifyCounter++;
	}
}

static int process_TRACE_line(char* linebuf, UINT64 lineno)
{
	int i;
	int ret = 0;
	UINT8 Operation;
	UINT64 Address;
	UINT8 Size;

	UINT64 RandValue64;

	// 删除行首、行尾空白回车等
	Trim(linebuf);
	int linelen = (int)strlen(linebuf);
	// 跳过空行
	if (linelen == 0)
		return 0;
	// 跳过超长的行
	if (linelen >= 100)
		return 0;
	// 跳过注释行
	if (linebuf[0] == '#' || linebuf[0] == '/' || linebuf[0] == '=' || linebuf[0] == '-')
		return 0;
	//printf("lineno=%llu\n", lineno);
	char** pt;
	int field_count;
	pt = split_space(linebuf, &field_count);

	if (field_count == 3 || field_count == 4)
	{
		// 格式： Operation Address,Size
		Operation = pt[0][0];
		if (field_count == 3)
		{
			Address = strtoull(pt[1], NULL, 16);
			Size = atoi(pt[2]);
		}
		else
		{
			Address = strtoull(pt[2], NULL, 16);
			Size = atoi(pt[3]);
		}

		if (Operation != 'I' && Operation != 'L' && Operation != 'S' && Operation != 'M')
		{
			if (VERBOSE_MSG)
				printf("[%s] line %lld 操作类型错误，不是I、L、S、M！ %s\n", __func__, lineno, linebuf);
			ret = -1;
		}
		else if (Size != 1 && Size != 2 && Size != 4 && Size != 8)
		{
			if (VERBOSE_MSG)
				printf("[%s] line %lld 数据大小错误，不是1、2、4、8！ %s\n", __func__, lineno, linebuf);
			ret = -1;
		}
		else
		{
			RandValue64 = GetRand64();

			// 初始化阶段，需要将所有地址的数据，设置为随机值
			WriteMemoryHash(Address, RandValue64, Size);

			if (MemoryTraceCounter >= MemoryTraceCapacity)
			{
				if (VERBOSE_MSG)
					printf("[%s] line %lld 扩展内存到%llu！\n", __func__, lineno, MemoryTraceCapacity + MEMORY_TRACE_CHUNK);
				MemoryTrace = (struct MemoryTraceStruct*)realloc(MemoryTrace, (MemoryTraceCapacity + MEMORY_TRACE_CHUNK) * sizeof(struct MemoryTraceStruct));
				if (MemoryTrace == NULL)
				{
					printf("[%s] line %lld 分配内存失败！\n", __func__, lineno);
					ret = -1;
				}
				else
					MemoryTraceCapacity += MEMORY_TRACE_CHUNK;
			}

			if (MemoryTrace)
			{
				MemoryTrace[MemoryTraceCounter].Operation = Operation;
				MemoryTrace[MemoryTraceCounter].Address = Address;
				MemoryTrace[MemoryTraceCounter].Size = Size;
				MemoryTraceCounter++;

				ret = 0;
			}
		}
	}
	else
	{
		printf("[%s] line %lld 格式错误！[fields=%d] %s\n", __func__, lineno, field_count, linebuf);
		ret = -1;
	}

	for (i = 0; i < field_count; i++)
		free(pt[i]);
	free(pt);
	return ret;
}

static int parse_TRACE_file(char* filename)
{
	UINT64 lineno;
	int ret_parse_line = 0;
	clock_t tick1, tick2;
	cbsl_errors cbsl_ret = cbsl_error;
	char linebuf[CHUNK];

	tick1 = clock();
	cbsl_ctx* ctx = cbsl_open(cbsl_load_mode, filename);
	if (ctx == NULL)
	{
		printf("[%s] 不能以读方式打开Trace文件 %s\n", __func__, filename);
		return -1;
	}

	lineno = 0;
	do
	{
		lineno++;
		cbsl_ret = cbsl_readline(ctx, linebuf, sizeof(linebuf));
		CBSL_ERROR_CHECK(cbsl_ret);	// 从文件中读取1行

		ret_parse_line = process_TRACE_line(linebuf, lineno);		// 分析处理1行
		if (ret_parse_line == 1 || cbsl_ret == cbsl_end)
			break;

		if (lineno % 10000 == 0)
		{
			printf("\33[?25l[%s] ====已处理%llu行====\r", __func__, lineno);	// 隐藏光标，显示进度
		}
	} while (1);

	printf("\n\33[?25h");	// 显示光标
	CBSL_ERROR_CHECK(cbsl_close(ctx));

	tick2 = clock();

	MemoryTraceStat();
	printf("[%s] +-----------------------------------------------------+\n", __func__);
	printf("[%s] |  Memory Trace数量                 \t : %10llu    |\n", __func__, MemoryTraceCounter);
	printf("[%s] |    Instruction操作数量            \t : %10llu    |\n", __func__, GlobalMemoryInstCounter);
	printf("[%s] |    Data Load操作数量              \t : %10llu    |\n", __func__, GlobalMemoryReadCounter);
	printf("[%s] |    Data Store操作数量             \t : %10llu    |\n", __func__, GlobalMemoryWriteCounter);
	printf("[%s] |    Data Modify操作数量            \t : %10llu    |\n", __func__, GlobalMemoryModifyCounter);
	printf("[%s] | 时间耗费（ms）                    \t : %10.0f    |\n", __func__, ((float)(tick2 - tick1) / CLOCKS_PER_SEC) * 1000.0);
	printf("[%s] +-----------------------------------------------------+\n", __func__);

	if (MemoryTraceCounter == 0)
		return -1;
	return 0;
}

int SimTrace()
{
	int ret = 0;
	UINT32 i;
	UINT8 Operation;
	UINT64 Address;
	UINT8 Size;

	UINT64 RandValue64;
	UINT64 DataFromCache;
	UINT64 DataFromMemory;
	UINT8 MissFlag;

	clock_t tick1, tick2;
	tick1 = clock();

	GlobalMemoryInstCounter = 0;
	GlobalMemoryReadCounter = 0;
	GlobalMemoryWriteCounter = 0;
	GlobalMemoryModifyCounter = 0;

	GlobalCacheInstHitCounter = 0;
	GlobalCacheReadHitCounter = 0;
	GlobalCacheWriteHitCounter = 0;
	GlobalCacheModifyHitCounter = 0;

	GlobalSimReadMemoryCounter = 0;
	GlobalSimWriteMemoryCounter = 0;

	for (i = 0; i < MemoryTraceCounter; i++)
	{
		Operation = MemoryTrace[i].Operation;
		Address = MemoryTrace[i].Address;
		Size = MemoryTrace[i].Size;

		if (Operation == 'L' || Operation == 'S' || Operation == 'M')
		{
			RandValue64 = GetRand64();
			MissFlag = AccessDataCache(Address, Operation, Size, RandValue64, &DataFromCache);
			if (Operation == 'S' || Operation == 'M')
			{
				WriteMemoryHash(Address, RandValue64, Size);
				if (Operation == 'S')
				{
					GlobalMemoryWriteCounter++;
					if (MissFlag == 'H')
					{
						GlobalCacheWriteHitCounter++;
					}
				}
				else if (Operation == 'M')
				{
					GlobalMemoryModifyCounter++;
					if (MissFlag == 'H')
					{
						GlobalCacheModifyHitCounter++;
					}
				}
			}
			else if (Operation == 'L')
			{
				GlobalMemoryReadCounter++;
				if (MissFlag == 'H')
				{
					DataFromMemory = ReadMemoryHash(Address, Size);
					if (DataFromMemory == DataFromCache)
						GlobalCacheReadHitCounter++;
					else
					{
						printf("[%s] 关键错误！数据Cache读错误，内存地址=%016llX 内存数据=%016llX Cache读数据=%016llX 大小%d字节\n", __func__, Address, DataFromMemory, DataFromCache, Size);
						ret = -1;
						break;
					}
				}
			}
		}
		else if (Operation == 'I')
		{
			MissFlag = AccessInstCache(Address, Operation, Size, &DataFromCache);
			GlobalMemoryInstCounter++;
			if (MissFlag == 'H')
			{
				DataFromMemory = ReadMemoryHash(Address, Size);
				if (DataFromMemory == DataFromCache)
					GlobalCacheInstHitCounter++;
				else
				{
					printf("[%s] 关键错误！指令Cache读错误，内存地址=%016llX 内存数据=%016llX Cache读数据=%016llX 大小%d字节\n", __func__, Address, DataFromMemory, DataFromCache, Size);
					ret = -1;
					break;
				}
			}
		}
	}
	tick2 = clock();
	printf("[%s] +-----------------------------------------------------+\n", __func__);
	printf("[%s] |  Memory Trace数量                \t : %10llu    |\n", __func__, MemoryTraceCounter);
	printf("[%s] |    Instruction操作数量           \t : %10llu    |\n", __func__, GlobalMemoryInstCounter);
	printf("[%s] |    Data Load操作数量             \t : %10llu    |\n", __func__, GlobalMemoryReadCounter);
	printf("[%s] |    Data Store操作数量            \t : %10llu    |\n", __func__, GlobalMemoryWriteCounter);
	printf("[%s] |    Data Modify操作数量           \t : %10llu    |\n", __func__, GlobalMemoryModifyCounter);
	printf("[%s] |    Instruction操作Cache命中数量  \t : %10llu    |\n", __func__, GlobalCacheInstHitCounter);
	printf("[%s] |    Data Load操作Cache命中数量    \t : %10llu    |\n", __func__, GlobalCacheReadHitCounter);
	printf("[%s] |    Data Store操作Cache命中数量   \t : %10llu    |\n", __func__, GlobalCacheWriteHitCounter);
	printf("[%s] |    Data Modify操作Cache命中数量  \t : %10llu    |\n", __func__, GlobalCacheModifyHitCounter);
	printf("[%s] |  Cache访存数量                   \t : %10llu    |\n", __func__, GlobalSimReadMemoryCounter + GlobalSimWriteMemoryCounter);
	printf("[%s] |    Cache读存储器数量             \t : %10llu    |\n", __func__, GlobalSimReadMemoryCounter);
	printf("[%s] |    Cache写存储器数量             \t : %10llu    |\n", __func__, GlobalSimWriteMemoryCounter);
	printf("[%s] |  Data Cache命中率                \t : %9.2f%%    |\n", __func__, (double)((GlobalCacheReadHitCounter + GlobalCacheWriteHitCounter + GlobalCacheModifyHitCounter) * 100) / (double)(GlobalMemoryReadCounter + GlobalMemoryWriteCounter + GlobalMemoryModifyCounter));
	printf("[%s] |  Inst Cache命中率                \t : %9.2f%%    |\n", __func__, (GlobalMemoryInstCounter == 0) ? 0 : (double)(GlobalCacheInstHitCounter * 100) / (double)GlobalMemoryInstCounter);
	printf("[%s] |  时间耗费（ms）                  \t : %10.0f    |\n", __func__, ((float)(tick2 - tick1) / CLOCKS_PER_SEC) * 1000.0);
	printf("[%s] +-----------------------------------------------------+\n", __func__);
	return ret;
}
void DisplayHelp(char* argv[])
{
	printf("[%s] 请在Cache.c中，实现你自己的Cache，然后编译项目，执行。\n", __func__);
	printf("[%s] 从文本格式压缩文件中读取Trace:\t%s <trace>.zst\n", __func__, argv[0]);
	printf("[%s]     例如: %s ./traces/dave.trace.zst\n", __func__, argv[0]);
	printf("[%s] 将文本格式的Trace转换到bin格式:\t%s -w <trace>.zst\n", __func__, argv[0]);
	printf("[%s] 从bin格式文件中读取Trace:\t\t%s -r <trace>.bin.zst\n", __func__, argv[0]);
	printf("[%s] 提示：从bin中读取Trace速度要远远快于从文本格式中读取。\n", __func__);
}

int main(int argc, char* argv[])
{
	int ret_val = -1;
	UINT8 ReadBinFileFlag, WriteBinFileFlag, ReadTxtFileFlag;
	char* pfilename;
	char pfilename_bin[CHUNK];
	clock_t tick1, tick2;
	UINT64 i;

	printf("[%s] Cache模拟器框架 v3.0 by mars, 2022\n", __func__);

	pfilename = NULL;
	ReadBinFileFlag = 0;
	WriteBinFileFlag = 0;
	ReadTxtFileFlag = 1;
	/* check arguments */
	while (1) {
		int c = getopt(argc, argv, "-hrw");
		if (c == -1) break;

		switch (c) {
		case 'h': DisplayHelp(argv); return 1;
		case 'r': ReadBinFileFlag = 1; ReadTxtFileFlag = 0; break;
		case 'w': WriteBinFileFlag = 1; ReadTxtFileFlag = 0; break;
		case 1: pfilename = optarg; break;
		}
	}

	if ((ReadBinFileFlag == 1 || WriteBinFileFlag == 1 || ReadTxtFileFlag == 1) && pfilename == NULL)
	{
		DisplayHelp(argv);
		return 1;
	}

	InitMemoryHash();
	printf("[%s] 初始化存储器，读入Trace文件[%s]，请稍后...\n", __func__, pfilename);

	if (ReadTxtFileFlag || WriteBinFileFlag)
	{
		MemoryTrace = (struct MemoryTraceStruct*)malloc(MEMORY_TRACE_CHUNK * sizeof(struct MemoryTraceStruct));
		MemoryTraceCounter = 0;
		MemoryTraceCapacity = MEMORY_TRACE_CHUNK;
		ret_val = parse_TRACE_file(pfilename);
		if (ret_val != 0)
		{
			FreeMemoryHash();
			if (MemoryTrace)
				free(MemoryTrace);
			printf("[%s] 解压缩文件失败 %s\n", __func__, argv[1]);
			return -1;
		}

		if (WriteBinFileFlag)
		{
			// 将内存中的MemoryTrace保存到bin文件中
			int filenamelen = (int)strlen(pfilename);
			memcpy(pfilename_bin, pfilename, filenamelen);
			pfilename_bin[filenamelen] = '\0';
			if (filenamelen > 5)
			{
				if ((pfilename_bin[filenamelen - 4] == '.' && pfilename_bin[filenamelen - 3] == 'z' && pfilename_bin[filenamelen - 2] == 's' && pfilename_bin[filenamelen - 1] == 't') ||
					(pfilename_bin[filenamelen - 4] == '.' && pfilename_bin[filenamelen - 3] == 'Z' && pfilename_bin[filenamelen - 2] == 'S' && pfilename_bin[filenamelen - 1] == 'T'))
				{
					pfilename_bin[filenamelen - 3] = 'b';
					pfilename_bin[filenamelen - 2] = 'i';
					pfilename_bin[filenamelen - 1] = 'n';
					pfilename_bin[filenamelen - 0] = '.';
					pfilename_bin[filenamelen + 1] = 'z';
					pfilename_bin[filenamelen + 2] = 's';
					pfilename_bin[filenamelen + 3] = 't';
					pfilename_bin[filenamelen + 4] = '\0';

					cbsl_ctx* ctx = cbsl_open(cbsl_store_mode, pfilename_bin);
					if (ctx == NULL)
					{
						printf("[%s] 不能以写方式打开文件 %s\n", __func__, pfilename_bin);
						ret_val = -1;
					}
					else
					{
						CBSL_ERROR_CHECK(cbsl_write(ctx, &MemoryTraceCounter, sizeof(MemoryTraceCounter)));
						CBSL_ERROR_CHECK(cbsl_write(ctx, MemoryTrace, MemoryTraceCounter * sizeof(struct MemoryTraceStruct)));
						CBSL_ERROR_CHECK(cbsl_close(ctx));
						printf("[%s] 已经将Trace保存到文件中 %s\n", __func__, pfilename_bin);
						ret_val = 0;
					}
				}
				else
				{
					printf("[%s] 文件扩展名不是.zst或者.ZST！不能转换！\n", __func__);
					ret_val = -1;
				}
			}
			else
			{
				printf("[%s] 文件名长度不足5字符！不能转换！\n", __func__);
				ret_val = -1;
			}

			FreeMemoryHash();
			if (MemoryTrace)
				free(MemoryTrace);
			return ret_val;
		}
	}
	else if (ReadBinFileFlag)
	{
		cbsl_ctx* ctx = cbsl_open(cbsl_load_mode, pfilename);
		if (ctx == NULL)
		{
			printf("[%s] 不能以读方式打开文件 %s\n", __func__, pfilename);
			ret_val = -1;
		}
		else
		{
			tick1 = clock();
			CBSL_ERROR_CHECK(cbsl_read(ctx, &MemoryTraceCounter, sizeof(MemoryTraceCounter)));
			{
				MemoryTrace = (struct MemoryTraceStruct*)malloc(MemoryTraceCounter * sizeof(struct MemoryTraceStruct));
				MemoryTraceCapacity = MemoryTraceCounter;

				CBSL_ERROR_CHECK(cbsl_read(ctx, MemoryTrace, MemoryTraceCounter * sizeof(struct MemoryTraceStruct)));
				CBSL_ERROR_CHECK(cbsl_close(ctx));
				{
					// 初始化阶段，需要将所有地址的数据，设置为随机值
					UINT64 RandValue64;
					for (i = 0; i < MemoryTraceCounter; i++)
					{
						RandValue64 = GetRand64();
						WriteMemoryHash(MemoryTrace[i].Address, RandValue64, MemoryTrace[i].Size);
					}

					MemoryTraceStat();
					tick2 = clock();
					printf("[%s] +-----------------------------------------------------+\n", __func__);
					printf("[%s] |  Memory Trace数量                 \t : %10llu    |\n", __func__, MemoryTraceCounter);
					printf("[%s] |    Instruction操作数量            \t : %10llu    |\n", __func__, GlobalMemoryInstCounter);
					printf("[%s] |    Data Load操作数量              \t : %10llu    |\n", __func__, GlobalMemoryReadCounter);
					printf("[%s] |    Data Store操作数量             \t : %10llu    |\n", __func__, GlobalMemoryWriteCounter);
					printf("[%s] |    Data Modify操作数量            \t : %10llu    |\n", __func__, GlobalMemoryModifyCounter);
					printf("[%s] | 时间耗费（ms）                    \t : %10.0f    |\n", __func__, ((float)(tick2 - tick1) / CLOCKS_PER_SEC) * 1000.0);
					printf("[%s] +-----------------------------------------------------+\n", __func__);
					printf("[%s] 已经将Trace从文件中读取 %s\n", __func__, pfilename);
					ret_val = 0;
				}
			}
		}

		if (ret_val == -1)
		{
			if (MemoryTrace)
				free(MemoryTrace);
			FreeMemoryHash();
			return ret_val;
		}
	}
	printf("[%s] 处理Trace文件完毕\n", __func__);
	InitDataCache();
	InitInstCache();
	printf("[%s] 开始Cache模拟，请稍后...\n", __func__);
	ret_val = SimTrace();
	if (ret_val != 0)
	{
		FreeMemoryHash();
		if (MemoryTrace)
			free(MemoryTrace);
		printf("[%s] Cache模拟失败\n", __func__);
		return -1;
	}
	else
		printf("[%s] Cache模拟成功完成\n", __func__);
	if (MemoryTrace)
		free(MemoryTrace);
	FreeMemoryHash();
	return 0;
}
