├── .gitignore ├── .gitmodules ├── LICENSE ├── README ├── README.md ├── after_run ├── README ├── graph │ ├── README │ ├── cg_histogram.py │ └── cg_pa_histogram.py ├── make_physical_trace.py ├── make_physical_trace_ts.py └── mix_vpmap.py ├── run_script ├── README ├── SeqW1G4K ├── check.sh ├── getopt.sh └── run_script.sh └── test ├── Synthetic_Workload ├── hashmap ├── hashmap.cpp ├── heap ├── heap.c ├── indirect_delta ├── indirect_delta.c ├── strided_latjob ├── strided_latjob.c ├── true_random └── true_random.c └── test_synthetic.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.deb 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "valgrind"] 2 | path = valgrind 3 | url = https://github.com/dgist-datalab/valgrind_cachetrace 4 | branch = master 5 | [submodule "kernel"] 6 | path = kernel 7 | url = https://github.com/dgist-datalab/cxl-kernel 8 | branch = cxl-minjae 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2023] [Minjae Kim] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This tool generates a virtual/physical address trace of the target application. 2 | 3 | [How to use] 4 | Step 1. Install Valgrind 5 | Go to valgrind/ dir and follow the install manual in the README. 6 | ** Note ** 7 | In the latest commit, Valgrind prints out timestamps of boot time for each trace line. 8 | If you don't want, comment out ./valgrind/callgrind/sim.c:153. 9 | //#define TRACE_TIMESTAMP 10 | 11 | Step 2. Install kernel in your system 12 | Go to kernel/ dir and run install.sh to install kernel build files. 13 | If you don't need physical trace, then skip Step 2. 14 | 15 | Step 3. Run target application with our script to generate raw trace file. 16 | You can use run_script.sh in the run_script/ dir. 17 | When you run run_script.sh with the target executable file as an input, 18 | the script will run Valgrind to generate after-cache virtual trace 19 | and send the target pid to the kernel to generate Virtual-Phyiscal mapping. 20 | Detailed manual is in the README in run_script/. 21 | 22 | In the current version, you can run only one target program at once for physical trace. 23 | 24 | Step 4. Create the physical address trace from raw trace files 25 | run_script.sh in Step 3 includes this Step 4. 26 | 27 | After step 3, you can get raw trace file, [.vout]. 28 | In step 4, you can get the physical trace file [.pout] by using the python script. 29 | Detailed manual is in the README in after_run/. 30 | 31 | After step 4, you will get [.pout] file as a final output. 32 | Format: [Read/Write] [Physical Address] 33 | Example: 34 | ... 35 | R 0x1234 36 | W 0x2345 37 | ... 38 | 39 | You can plot some graphs with trace files by using after_run/graph/*.py 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Trace Generator (Memory Tracing Tool) 2 | A memory tracing tool generating a virtual/physical address trace of the target aplication. 3 | This repository is focused on working together as a part of the [CXL-flash Design Tools](https://github.com/spypaul/MQSim_CXL) used in our research paper, _Overcoming the Memory Wall with CXL-Enabled SSDs_. 4 | 5 | ## Goal 6 | The goal of this memory tracing tool is generating raw memory trace files (`*.vout` or `*.pout`). 7 | To use MQSim_CXL in [CXL-flash Design Tools](https://github.com/spypaul/MQSim_CXL), the raw trace files generated from this tool should be translated to `*.trace` files by using [Trace Translator](https://github.com/spypaul/trace_translation). 8 | 9 | ## Installation 10 | This memory tracing tool is composed of three main components: a modified version of Valgrind, the Linux kernel, and scripts to facilitate its use. 11 | Repositories of the modified version of Valgrind and Linux kernel are submodules of this repository, and they follow their own licenses, GPL v2. 12 | 13 | ### The modified version of Valgrind 14 | 1. Clone [the github repository](https://github.com/dgist-datalab/valgrind_cachetrace/tree/040053890262abac1b504bbd5cd9ace8e2261a4e) 15 | ``` 16 | $ git clone https://github.com/dgist-datalab/valgrind_cachetrace.git 17 | $ cd valgrind_cachetrace 18 | ``` 19 | 2. Install the modified version of Valgrind 20 | ``` 21 | $ ./autogen.sh 22 | $ ./configure 23 | $ make 24 | $ sudo make install 25 | ``` 26 | 27 | ### Linux Kernel 28 | * If you don't need physical traces, don't need to install this Linux kernel. 29 | * The `defconfig` used in our forked kernel is located at `arch/x86/configs/ubuntu_defconfig`. 30 | 1. Clone [the github repository](https://github.com/dgist-datalab/cxl-kernel/tree/220990494efb831170a0dd60b45bd8afeea2d023) 31 | ``` 32 | $ git clone https://github.com/dgist-datalab/cxl-kernel.git 33 | $ cd cxl-kernel 34 | ``` 35 | 2. Build & install the Linux kernel 36 | ``` 37 | $ cp arch/x86/configs/ubuntu_defconfig .config 38 | $ make bindeb-pkg -j64 39 | $ cd ../ 40 | $ dpkg -i linux-headers-5.17.4-... linux-image-5.17.4-... 41 | $ reboot 42 | ... 43 | ``` 44 | 45 | ## Test 46 | * `test/` directory includes a script generating raw trace files (`*.vout` or `*.pout`) of Synthetic workloads automatically. 47 | * When you run `test_synthetic.sh`, you can select which synthetic workload to run and generate only a virtual memory trace or both virtual/physical traces. 48 | ``` 49 | $ cd test/ 50 | $ sudo ./test_synthetic.sh 51 | ``` 52 | * After generating the trace file, you can plot a rough figure showing the memory address distribution of the trace file. 53 | ``` 54 | python3 after_run/graph/cg_histogram.py --input [.vout] --scatter 103 55 | python3 after_run/graph/cg_pa_histogram.py --input [.pout] --scatter 103 56 | ``` 57 | 58 | * If you want to generate trace files of your target applications, run `run_script/run_script.sh` with your target applications following [README](https://github.com/dgist-datalab/trace_generator/tree/main/run_script). 59 | 60 | ### Test Output 61 | * Raw trace files: `*.vout`, `*.pout`. 62 | * These raw trace files are the input files for [Trace Translator](https://github.com/spypaul/trace_translation). 63 | * [Trace Translator](https://github.com/spypaul/trace_translation) translates these raw trace files to trace files for [MQSim_CXL](https://github.com/spypaul/MQSim_CXL). 64 | -------------------------------------------------------------------------------- /after_run/README: -------------------------------------------------------------------------------- 1 | make_physical_trace.py 2 | usage: python3 make_physical_trace.py [trace.mix] 3 | output: trace.phyout 4 | 5 | the [.mix] trace file has two information. One is a virtual address trace, and the other is Virtual-Phyiscal mappings. 6 | This code combines two information and generates a physical address trace. 7 | 8 | The first line of [.pout] file: 9 | ok_cnt none_cnt ok/total 10 | 11 | make_physical_trace_ts.py 12 | usage: python3 make_physical_trace_ts.py [trace.mix] 13 | output: trace.phyout 14 | 15 | This script is the same as the one above, but is used when the [.mix] trace file contains timestamps. 16 | Only line 160 is different. 17 | 18 | mix_vpmap.py 19 | usage: python3 mix_vpmap.py [trace.vout] 20 | output: trace.mix 21 | 22 | This script makes [.mix] trace file by combining [trace.vout] and [trace.vpmap] 23 | -------------------------------------------------------------------------------- /after_run/graph/README: -------------------------------------------------------------------------------- 1 | Plot graphs with generated trace. 2 | 3 | cg_histogram.py 4 | Input: [.vout] trace file from Step 3 5 | Output: [.eps] graph and log files 6 | 7 | python3 cg_histogram.py -i [trace.out] 8 | plot graph (VA - # of accesses) 9 | python3 cg_histogram.py -i [trace.out] --cdf 10 | plot sorted cdf graph (VA - # of accesses) 11 | python3 cg_histogram.py -i [trace.out] --scatter [sampling unit] 12 | plot graph (elapsed time - VA) 13 | 14 | 15 | cg_pa_histogram.py 16 | Input: [.pout] trace file from Step 4 and log files. You need to run cg_historam.py first to create log files. 17 | Output: [.eps] graph files. 18 | 19 | python3 cg_pa_histogram.py -i [trace.phyout] 20 | plot graph (PA - # of accesses) 21 | python3 cg_pa_histogram.py -i [trace.phyout] --cdf 22 | plot sorted cdf graph (PA - # of accesses) 23 | python3 cg_pa_histogram.py -i [trace.phyout] --scatter [sampling unit] 24 | plot graph (elapsed time - PA) 25 | -------------------------------------------------------------------------------- /after_run/graph/cg_histogram.py: -------------------------------------------------------------------------------- 1 | from tokenize import group 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | import sys 5 | import argparse 6 | from itertools import accumulate 7 | 8 | def file_len(fname): 9 | with open(fname) as f: 10 | for i, l in enumerate(f): 11 | pass 12 | return i + 1 13 | 14 | def save_log(fname, min, max, lower_bound, upper_bound, group_num, data=0): 15 | log_file = open(fname, 'w') 16 | log_file.write(str(hex(min)) + " " + str(hex(max)) + "\n") 17 | log_file.write(str(hex(lower_bound) + " " + str(hex(upper_bound))) + "\n") 18 | log_file.write("group_num " + str(group_num) + "\n") 19 | if data: 20 | log_file.write("ydata" + "\n") 21 | log_file.write(str(data).replace('[', '').replace(']', '').replace(',', '')) 22 | log_file.close() 23 | 24 | parser = argparse.ArgumentParser() 25 | parser.add_argument("-i", "--input", action='store', type=str, help='input file', default=False) 26 | parser.add_argument("-c", "--cdf", action='store_true', help='plot sorted cdf', default=False) 27 | parser.add_argument("-s", "--scatter", action='store', type=int, help='plot scattered graph', default=False) 28 | args = parser.parse_args() 29 | input_file_name = args.input 30 | scatter=0; cdf=0 31 | if args.scatter: 32 | scatter = 1 33 | print("plot scattered order-address graph") 34 | else: 35 | if args.cdf: 36 | cdf = 1 37 | print("plot sorted cdf graph") 38 | else: 39 | print("plot basic address histogram") 40 | 41 | input_file_name = args.input 42 | if input_file_name[-5:] != ".vout": 43 | print("input file [%s] is not .vout!" % (input_file_name)) 44 | exit() 45 | 46 | linenum = file_len(input_file_name) 47 | print("linenum of %s: %d" % (input_file_name, linenum)) 48 | 49 | # File open, and find min, max for specifying bound 50 | #input_file_name = "ldst_result" 51 | file = open(input_file_name, 'r') 52 | file.seek(0) 53 | 54 | i = 0 55 | min = 0xffffffffffffffff 56 | max = 0 57 | upper_bound = 0x1000000000 58 | lower_bound = 0x100000 59 | print("Find min/max of address..") 60 | while True: 61 | line = file.readline() 62 | if not line: break 63 | if line[0] == "=" or line[0] == "-": continue 64 | if (i % (linenum//1000)) == 0: 65 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 66 | #if i>100: exit() 67 | 68 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 69 | splitline = line.split("{") 70 | #del splitline[0] 71 | item = splitline[-1] 72 | #for item in splitline[::-1]: 73 | elem = item.split(" ") 74 | elem = ' '.join(elem).split() 75 | if elem[0] == 'R' or elem[0] == 'W': 76 | a = int(elem[1], 16) 77 | if a > max: 78 | if a < upper_bound: # Upper bound of interesting address 79 | max = a 80 | if a < min: 81 | if a > lower_bound: # Lower bound of interesting address 82 | min = a 83 | """ 84 | line = line.replace('[R ', '').replace('[W ', '').replace(']', '').replace('\n',' ') 85 | a = int(line, 16) 86 | 87 | if a > max: 88 | if a < upper_bound: # Upper bound of interesting address 89 | max = a 90 | if a < min: 91 | if a > lower_bound: # Lower bound of interesting address 92 | min = a 93 | """ 94 | 95 | i += 1 96 | #min= 0x100248; max= 0x158c60000 97 | 98 | print("min:", hex(min), "max:", hex(max)) 99 | file.close() 100 | 101 | # File open, and make histogram (# of access per address group) 102 | file = open(input_file_name, 'r') 103 | 104 | va_pool_size = max-min 105 | #group_size = 4096 # Pagesize 106 | #va_group_num = va_pool_size // group_size 107 | 108 | group_num = 10000 109 | #group_num = va_group_num 110 | group_size = va_pool_size // group_num 111 | print("group_size:", group_size, "group_num:", group_num) 112 | 113 | if scatter: 114 | # create scatter list 115 | scope = max-min 116 | i = 0 117 | scatter = [] 118 | print("Make scatter list..") 119 | while True: 120 | line = file.readline() 121 | if not line: break 122 | if line[0] == "=" or line[0] == "-": continue 123 | if (i % (linenum//1000)) == 0: 124 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 125 | 126 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 127 | elem = line.split("{")[-1].split(" ") 128 | elem = ' '.join(elem).split() 129 | if elem[0] == 'R' or elem[0] == 'W': 130 | a = int(elem[1], 16) 131 | if a >= upper_bound or a <= lower_bound: 132 | i += 1 133 | continue 134 | group_idx = round((a-min)/scope*group_num) 135 | scatter.append(group_idx) 136 | i += 1 137 | print("len(scatter):", len(scatter)) 138 | file.close() 139 | 140 | # scatter plot 141 | samp_per = args.scatter 142 | samp = [] 143 | for i in range(len(scatter)): 144 | if i % samp_per == 0: 145 | samp.append(scatter[i]) 146 | print("len(samp):", len(samp)) 147 | 148 | x = list(np.arange(0, len(samp), 1)) 149 | 150 | #plt.rcParams["font.family"] = 'Times New Roman' 151 | plt.rcParams["font.size"] = 22 152 | plt.rcParams["figure.figsize"] = (8,5) 153 | plt.rc('legend', fontsize=18) 154 | 155 | fig, ax1 = plt.subplots(dpi=600) 156 | #plt.xticks(x, label, fontsize=20) 157 | 158 | x_ = x[:] 159 | scatter_ = samp[:] 160 | #x = x[:80] 161 | #hist = hist[:80] 162 | ax1.scatter(x, scatter_, c='black', s=1) 163 | 164 | #ax1.bar(x_, scatter_, width=0.2, edgecolor='black', linewidth=1, zorder=1) 165 | 166 | xlabel_name = 'Order of requests (sampled per ' + str(samp_per) + ' requests)' 167 | ylabel_name="Virtual address group \n(" + str(group_num) + " groups, "+str(group_size)+"B)" 168 | ax1.set_xlabel(xlabel_name) 169 | ax1.set_ylabel(ylabel_name) 170 | ax1.tick_params(axis='y', direction='in') 171 | ax1.set_ylim(0, group_num) 172 | id_str = "-scatter"+str(args.scatter)+"-g"+str(group_num)+"-"+str(group_size) 173 | fig_name = "./plot" + id_str + "_" + input_file_name[:-5] + "_va.png" 174 | fig.savefig(fig_name, bbox_inches='tight', format='png') 175 | log_file_name = input_file_name[:-5] + ".slog" 176 | save_log(log_file_name, min, max, lower_bound, upper_bound, group_num, data=scatter) 177 | 178 | 179 | 180 | 181 | else: 182 | 183 | scope = max-min 184 | i = 0 185 | hist = [0 for i in range(group_num+1)] # group: [0,100] 186 | print("Make histogram list..") 187 | while True: 188 | line = file.readline() 189 | if not line: break 190 | if line[0] == "=" or line[0] == "-": continue 191 | if (i % (linenum//1000)) == 0: 192 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 193 | 194 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 195 | elem = line.split("{")[-1].split(" ") 196 | elem = ' '.join(elem).split() 197 | if elem[0] == 'R' or elem[0] == 'W': 198 | a = int(elem[1], 16) 199 | if a >= upper_bound or a <= lower_bound: 200 | i += 1 201 | continue 202 | percent = round((a-min)/scope*group_num) 203 | hist[percent] += 1 204 | 205 | """ 206 | # Integrate read/write as an access 207 | line = line.replace('[R ', '').replace('[W ', '').replace(']', '').replace('\n',' ') 208 | a = int(line, 16) 209 | if a >= upper_bound or a <= lower_bound: 210 | i += 1 211 | continue 212 | 213 | percent = round((a-min)/scope*group_num) # 100 groups 214 | #percent = round((a-min)/scope*1000) # 1000 groups 215 | hist[percent] += 1 216 | """ 217 | 218 | i += 1 219 | 220 | file.close() 221 | 222 | if cdf == 1: 223 | sorted = 1 224 | hist.sort() 225 | sum_hist = sum(hist) 226 | cd = list(accumulate(hist)) 227 | for i in range(len(cd)): 228 | cd[i] = cd[i]/sum_hist 229 | hist = cd 230 | else: 231 | sorted = 0 232 | 233 | # Make histogram 234 | x = list(np.arange(0, group_num+1, 1)) 235 | 236 | #plt.rcParams["font.family"] = 'Times New Roman' 237 | plt.rcParams["font.size"] = 22 238 | plt.rcParams["figure.figsize"] = (8,5) 239 | plt.rc('legend', fontsize=18) 240 | 241 | fig, ax1 = plt.subplots(dpi=600) 242 | 243 | x_ = x[:] 244 | hist_ = hist[:] 245 | #x_ = x[20:80] # See 20% ~ 80% 246 | #hist_ = hist[20:80] 247 | ax1.bar(x_, hist_, width=0.2, edgecolor='black', linewidth=1, zorder=1) 248 | 249 | if sorted == 1: 250 | xlabel_name="Virtual address groups (" + str(group_num) + " groups, "+str(group_size)+"B, sorted)" 251 | else: 252 | xlabel_name="Virtual address groups (" + str(group_num) + " groups, "+str(group_size)+"B)" 253 | ax1.set_xlabel(xlabel_name) 254 | if cdf == 1: 255 | ax1.set_ylabel('CDF (# of accesses)') 256 | id_str = "-cdf-g"+str(group_num)+"-"+str(group_size) 257 | else: 258 | ax1.set_ylabel('# of accesses') 259 | id_str = "-g"+str(group_num)+"-"+str(group_size) 260 | ax1.tick_params(axis='y', direction='in') 261 | 262 | fig_name = "./hist" + id_str + "_" + input_file_name[:-5] + "_va.png" 263 | fig.savefig(fig_name, bbox_inches='tight', format='png') 264 | 265 | # Save min/max in a log file for calculating the address pool size 266 | if cdf == 1: 267 | log_file_name = input_file_name[:-5] + ".clog" 268 | else: 269 | log_file_name = input_file_name[:-5] + ".blog" 270 | save_log(log_file_name, min, max, lower_bound, upper_bound, group_num, data=hist) 271 | -------------------------------------------------------------------------------- /after_run/graph/cg_pa_histogram.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import sys 4 | import argparse 5 | from itertools import accumulate 6 | 7 | def file_len(fname): 8 | with open(fname) as f: 9 | for i, l in enumerate(f): 10 | pass 11 | return i + 1 12 | 13 | def read_va_log(input_file_name, args, data_read = 0): 14 | # From VA histogram log file, calculate each group size 15 | if args.scatter > 0: 16 | log_ext = ".slog" 17 | elif args.cdf: 18 | log_ext = ".clog" 19 | else: 20 | log_ext = ".blog" 21 | va_log_file_name = input_file_name[:-5] + log_ext 22 | va_log_file = open(va_log_file_name, 'r') 23 | splitline = va_log_file.readline().split(" ") 24 | va_min = int(splitline[0], 16) 25 | va_max = int(splitline[1], 16) 26 | splitline = va_log_file.readline().split(" ") 27 | va_lower_bound = int(splitline[0], 16) 28 | va_upper_bound = int(splitline[1], 16) 29 | splitline = va_log_file.readline().split(" ") 30 | va_group_num = int(splitline[1], 10) 31 | va_log_file.readline() 32 | splitline = va_log_file.readline().split(" ") 33 | va_hist = [] 34 | if data_read == 1 and args.cdf == 0: 35 | for y in splitline: 36 | va_hist.append(int(y)) 37 | va_log_file.close() 38 | return va_min, va_max, va_lower_bound, va_upper_bound, va_group_num, va_hist 39 | 40 | parser = argparse.ArgumentParser() 41 | parser.add_argument("-i", "--input", action='store', type=str, help='input file', default=False) 42 | parser.add_argument("-c", "--cdf", action='store_true', help='plot sorted cdf', default=False) 43 | parser.add_argument("-s", "--scatter", action='store', type=int, help='plot scattered graph', default=False) 44 | args = parser.parse_args() 45 | input_file_name = args.input 46 | scatter=0; cdf=0 47 | if args.scatter: 48 | scatter = 1 49 | print("plot scattered order-address graph") 50 | else: 51 | if args.cdf: 52 | cdf = 1 53 | print("plot sorted cdf graph") 54 | else: 55 | print("plot basic address histogram") 56 | 57 | input_file_name = args.input 58 | #input_file_name = sys.argv[1] 59 | if input_file_name[-5:] != ".pout": 60 | print("input file [%s] is not .phyout!" % (input_file_name)) 61 | exit() 62 | 63 | linenum = file_len(input_file_name) 64 | print("linenum of %s: %d" % (input_file_name, linenum)) 65 | 66 | # File open, and find min, max for specifying bound 67 | file = open(input_file_name, 'r') 68 | 69 | i = 0 70 | min = 0xffffffffffffffff 71 | max = 0 72 | upper_bound = 0x1000000000 73 | #upper_bound = 0x350000000 74 | lower_bound = 0x100000 75 | 76 | print("Find min/max of address..") 77 | file.readline() 78 | while True: 79 | line = file.readline() 80 | if not line: break 81 | if line[0] == "=" or line[0] == "-": continue 82 | if (i % (linenum//1000)) == 0: 83 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 84 | 85 | line = line.replace('R ', '').replace('W ', '').replace('\n',' ') 86 | splitline = line.split(" ") 87 | a = int(splitline[0], 16) 88 | 89 | if a > max: 90 | if a < upper_bound: # Upper bound of interesting address 91 | max = a 92 | if a < min: 93 | if a > lower_bound: # Lower bound of interesting address 94 | min = a 95 | 96 | i += 1 97 | 98 | print("min:", hex(min), "max:", hex(max)) 99 | group_num = 100000 100 | 101 | # From VA histogram log file, calculate each group size 102 | va_min, va_max, va_lower_bound, va_upper_bound, va_group_num, va_data = read_va_log(input_file_name, args, data_read = 1) 103 | #//print("sum(va_hist): %d" % (sum(va_hist))) 104 | 105 | va_pool_size = va_max - va_min 106 | va_group_size = va_pool_size // va_group_num 107 | pa_pool_size = max - min 108 | pa_group_size1 = pa_pool_size // group_num # static group size 109 | pa_group_size2 = va_group_size 110 | group_num2 = pa_pool_size // pa_group_size2 111 | group_weight = group_num2 // va_group_num // 2 112 | precise_plot = 0 113 | print("group_num (va/static_pa/precise_pa): %d/%d/%d, group_weight: %d, va_group_size: %d, pa_group_size (static/precise): %d/%d" % (va_group_num, group_num, group_num2, group_weight, va_group_size, pa_group_size1, pa_group_size2)) 114 | if precise_plot == 0: 115 | print("For precise plotting, use same group size with virtual trace") 116 | group_num = group_num2 117 | group_size = pa_group_size2 118 | else: 119 | group_size = pa_group_size1 120 | # histogram 자체를 group_weight 개수만큼 나눠야 할 것 같긴 하다. 121 | 122 | 123 | # File open, and make histogram (# of access per address group) 124 | file.seek(0) 125 | 126 | man = 0 # manual size of axis 127 | man_range = 10000 128 | if scatter: 129 | scope = max-min 130 | i = 0 131 | scatter = [] 132 | R_cnt = 0 133 | W_cnt = 0 134 | 135 | print("Make scatter list..") 136 | file.readline() 137 | while True: 138 | line = file.readline() 139 | if not line: break 140 | if line[0] == "=" or line[0] == "-": continue 141 | if (i % (linenum//1000)) == 0: 142 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 143 | 144 | # Integrate read/write as an access 145 | if line[0] == 'R': 146 | R_cnt += 1 147 | elif line[0] == 'W': 148 | W_cnt += 1 149 | 150 | line = line.replace('R ', '').replace('W ', '').replace('\n',' ') 151 | splitline = line.split(" ") 152 | a = int(splitline[0], 16) 153 | if a >= upper_bound or a <= lower_bound: 154 | i += 1 155 | continue 156 | 157 | group_idx = round((a-min)/scope*group_num) 158 | scatter.append(group_idx) 159 | i += 1 160 | print("len(scatter):", len(scatter)) 161 | file.close() 162 | 163 | print("R_cnt: %d, W_cnt: %d, Total: %d" % (R_cnt, W_cnt, R_cnt+W_cnt)) 164 | sum_scatter = sum(scatter) 165 | print("sum(scatter): %d" % (sum_scatter)) 166 | 167 | 168 | # scatter plot 169 | samp_per = args.scatter 170 | samp = [] 171 | for i in range(len(scatter)): 172 | if i % samp_per == 0: 173 | samp.append(scatter[i]) 174 | print("len(samp):", len(samp)) 175 | 176 | x = list(np.arange(0, len(samp), 1)) 177 | 178 | figsize_x = 8; figsize_y = 5 179 | if precise_plot == 1: 180 | figsize_x = figsize_x * group_weight 181 | #plt.rcParams["font.family"] = 'Times New Roman' 182 | plt.rcParams["font.size"] = 22 183 | plt.rcParams["figure.figsize"] = (figsize_x, figsize_y) 184 | plt.rc('legend', fontsize=18) 185 | 186 | fig, ax1 = plt.subplots(dpi=600) 187 | 188 | #x_ = x[10000:15000] 189 | #hist_ = hist[10000:15000] 190 | x_ = x[:] 191 | scatter_ = samp[:] 192 | #x_ = x[20:80] # See 20% ~ 80% 193 | #hist_ = hist[20:80] 194 | 195 | 196 | print("plot..") 197 | ax1.scatter(x, scatter_, c='black', s=1) 198 | xlabel_name = 'Order of requests (sampled per ' + str(samp_per) + ' requests)' 199 | ylabel_name="Physical address group \n(" + str(group_num) + " groups, "+str(group_size)+"B)" 200 | ax1.set_xlabel(xlabel_name) 201 | ax1.set_ylabel(ylabel_name) 202 | ax1.tick_params(axis='y', direction='in') 203 | if man == 0: 204 | ax1.set_ylim(0, group_num) 205 | else: 206 | ax1.set_ylim(0, man_range) # add "man" in fig_name 207 | 208 | print("plot end. save..") 209 | id_str = "-scatter"+str(args.scatter)+"-g"+str(group_num)+"-"+str(group_size) 210 | if man == 0: 211 | fig_name = "./plot" + id_str + "_" + input_file_name[:-5] + "_pa.png" 212 | else: 213 | fig_name = "./manplot" + id_str + "_" + input_file_name[:-5] + "_pa.png" 214 | fig.savefig(fig_name, bbox_inches='tight', format='png') 215 | 216 | else: 217 | scope = max-min 218 | i = 0 219 | hist = [0 for i in range(group_num+1)] # group: [0,100] 220 | R_cnt = 0 221 | W_cnt = 0 222 | 223 | print("Make histogram list..") 224 | file.readline() 225 | while True: 226 | line = file.readline() 227 | if not line: break 228 | if line[0] == "=" or line[0] == "-": continue 229 | if (i % (linenum//1000)) == 0: 230 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 231 | 232 | # Integrate read/write as an access 233 | if line[0] == 'R': 234 | R_cnt += 1 235 | elif line[0] == 'W': 236 | W_cnt += 1 237 | 238 | line = line.replace('R ', '').replace('W ', '').replace('\n',' ') 239 | a = int(line, 16) 240 | if a >= upper_bound or a <= lower_bound: 241 | i += 1 242 | continue 243 | 244 | percent = round((a-min)/scope*group_num) 245 | hist[percent] += 1 246 | 247 | i += 1 248 | 249 | file.close() 250 | print("R_cnt: %d, W_cnt: %d, Total: %d" % (R_cnt, W_cnt, R_cnt+W_cnt)) 251 | sum_hist = sum(hist) 252 | print("sum(hist): %d" % (sum_hist)) 253 | va_hotgroup_cnt = 0; va_hotgroup_sum = 0 254 | hotgroup_cnt = 0; hotgroup_sum = 0 255 | for y in va_data: 256 | if y > 5000: 257 | va_hotgroup_cnt += 1 258 | va_hotgroup_sum += y 259 | for y in hist: 260 | if y > 5000: 261 | hotgroup_cnt += 1 262 | hotgroup_sum += y 263 | print("va_hotgroup_cnt: %d, hotgroup_cnt: %d" % (va_hotgroup_cnt, hotgroup_cnt)) 264 | print("va_hotgroup_sum: %d, hotgroup_sum: %d" % (va_hotgroup_sum, hotgroup_sum)) 265 | # group size가 어쨌든 4K pagesize보다는 크므로, 266 | # MMU가 VPN을 page 단위로 퍼뜨린다고 가정하면 더 퍼뜨리는 것처럼 보일 수 있다. 267 | # 이것까지 제대로 보려면, 애초에 VA hist에서 group size를 group_num=10000이 아니라 268 | # group_size=4000으로 해야 한다. 269 | 270 | # Sort and cdf 271 | from itertools import accumulate 272 | 273 | if cdf == 1: 274 | sorted = 1 275 | if man == 1: 276 | hist = hist[:man_range] 277 | hist.sort() 278 | sum_hist = sum(hist) 279 | cd = list(accumulate(hist)) 280 | for i in range(len(cd)): 281 | cd[i] = cd[i]/sum_hist 282 | hist = cd 283 | else: 284 | sorted = 0 285 | 286 | # Make histogram 287 | if cdf == 0: 288 | x = list(np.arange(0, group_num+1, 1)) 289 | else: 290 | if man == 1: 291 | x = list(np.arange(0, man_range, 1)) 292 | else: 293 | x = list(np.arange(0, group_num+1, 1)) 294 | 295 | figsize_x = 8; figsize_y = 5 296 | if precise_plot == 1: 297 | figsize_x = figsize_x * group_weight 298 | #plt.rcParams["font.family"] = 'Times New Roman' 299 | plt.rcParams["font.size"] = 22 300 | plt.rcParams["figure.figsize"] = (figsize_x, figsize_y) 301 | plt.rc('legend', fontsize=18) 302 | 303 | fig, ax1 = plt.subplots(dpi=600) 304 | 305 | #x_ = x[10000:15000] 306 | #hist_ = hist[10000:15000] 307 | x_ = x[:] 308 | hist_ = hist[:] 309 | #x_ = x[20:80] # See 20% ~ 80% 310 | #hist_ = hist[20:80] 311 | 312 | 313 | print("plot..") 314 | ax1.bar(x_, hist_, width=0.2, edgecolor='black', linewidth=1, zorder=1) 315 | 316 | if man == 1: 317 | if cdf == 1: 318 | ax1.set_xlim(man_range-10000, man_range) # add "man" in fig_name 319 | else: 320 | ax1.set_xlim(0, man_range) # add "man" in fig_name 321 | 322 | if sorted == 1: 323 | xlabel_name="Physical address groups (" + str(group_num) + " groups, "+str(group_size)+"B, sorted)" 324 | else: 325 | xlabel_name="Physical address groups (" + str(group_num) + " groups, "+str(group_size)+"B)" 326 | ax1.set_xlabel(xlabel_name) 327 | #ax1.set_xlabel('Physical address groups (1,000,000 groups)') 328 | if cdf == 1: 329 | ax1.set_ylabel('CDF (# of accesses)') 330 | id_str = "-cdf-g"+str(group_num)+"-"+str(group_size) 331 | else: 332 | ax1.set_ylabel('# of accesses') 333 | id_str = "-g"+str(group_num)+"-"+str(group_size) 334 | ax1.tick_params(axis='y', direction='in') 335 | 336 | print("plot end. save..") 337 | if man == 0: 338 | fig_name = "./hist" + id_str + "_" + input_file_name[:-5] + "_pa.png" 339 | else: 340 | fig_name = "./manhist" + id_str + "_" + input_file_name[:-5] + "_pa.png" 341 | fig.savefig(fig_name, bbox_inches='tight', format='png') 342 | -------------------------------------------------------------------------------- /after_run/make_physical_trace.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import sys 4 | 5 | def file_len(fname): 6 | with open(fname) as f: 7 | for i, l in enumerate(f): 8 | pass 9 | return i + 1 10 | 11 | def find_close_mapping(x, a): 12 | target = 0 13 | close = 50 14 | small = 0 15 | big = len(a)-1 16 | for i in range(len(a)): 17 | if (a[i]) < x: 18 | small = i 19 | if a[i] >= x: 20 | big = i 21 | break 22 | diff_s = x-a[small] 23 | diff_b = a[big]-x 24 | 25 | if small == 0 and big == 0: 26 | target = small 27 | elif small == big and small > 0: 28 | target = big 29 | else: 30 | if diff_s < 0 or diff_b < 0: 31 | print("Error (diff_s: %d, diff_b: %d)" % (diff_s, diff_b)) 32 | elif diff_s < close and diff_b < close: 33 | target = small if diff_s <= diff_b else big 34 | elif diff_s < close: 35 | target = small 36 | elif diff_b < close: 37 | target = big 38 | return target 39 | 40 | 41 | 42 | input_file_name = sys.argv[1] 43 | linenum = file_len(input_file_name) 44 | print("linenum of %s: %d" % (input_file_name, linenum)) 45 | 46 | if input_file_name[-4:] != ".out": 47 | print("input file [%s] is not .out!" % (input_file_name)) 48 | exit() 49 | 50 | raw_trace_file = open(input_file_name, 'r') 51 | for i in range(7): 52 | line = raw_trace_file.readline() 53 | 54 | i = 0 55 | d = {} 56 | d.clear() 57 | item_idx = {} 58 | item_idx.clear() 59 | item_cnt = 0 60 | map_cnt = 0 61 | vpn_cnt = 0 62 | exist_cnt = 0 63 | 64 | # make v2p map (dictionary) 65 | while True: 66 | line = raw_trace_file.readline() 67 | if not line: break 68 | if (i % (linenum//1000)) == 0: 69 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 70 | 71 | num_cg = line.count('[') 72 | num_kn = line.count('{') 73 | num_total = num_cg + num_kn 74 | 75 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 76 | 77 | splitline = line.split("{") 78 | del splitline[0] 79 | 80 | for item in splitline: 81 | 82 | elem = item.split(" ") 83 | elem = ' '.join(elem).split() 84 | if elem[0] == 'R' or elem[0] == 'W': 85 | cg_vaddr = int(elem[1], 16) 86 | else: 87 | map_cnt += 1 88 | kn_vpn = int(elem[2], 16) 89 | kn_pfn = int(elem[3], 16) 90 | if kn_vpn in d: 91 | d[kn_vpn].append([item_cnt, kn_pfn]) 92 | exist_cnt += 1 93 | else: 94 | d[kn_vpn] = [[item_cnt, kn_pfn]] 95 | vpn_cnt += 1 96 | item_cnt += 1 97 | 98 | i += 1 99 | 100 | #raw_trace_file.close() 101 | 102 | 103 | 104 | # Second scan to translate Valgrind's virtual memory trace to the physical memory trace 105 | output_file_name = input_file_name[:-4] + ".phyout" 106 | mem_trace = open(output_file_name, 'w') 107 | raw_trace_file.seek(0) 108 | 109 | for i in range(7): 110 | line = raw_trace_file.readline() 111 | 112 | i = 0 113 | item_cnt = 0 114 | none_cnt = 0 115 | ok_cnt = 0 116 | find_flag = 0 117 | variable_map_cnt = 0 118 | 119 | while True: 120 | line = raw_trace_file.readline() 121 | if not line: break 122 | if (i % (linenum//1000)) == 0: 123 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 124 | 125 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 126 | 127 | splitline = line.split("{") 128 | del splitline[0] 129 | 130 | for item in splitline: 131 | elem = item.split(" ") 132 | elem = ' '.join(elem).split() 133 | 134 | if elem[0] == 'R' or elem[0] == 'W': 135 | cg_vaddr = int(elem[1], 16) 136 | cg_vpn = cg_vaddr // 4096 137 | cg_ofs = cg_vaddr & 0xfff 138 | 139 | if (d.get(cg_vpn) == None): 140 | none_cnt += 1 141 | else: 142 | val = d[cg_vpn] 143 | if len(val) > 1: 144 | idx_list = [] 145 | for j in range(len(val)): 146 | idx_list.append(val[j][0]) 147 | target_j = find_close_mapping(item_cnt, idx_list) 148 | kn_pfn = val[target_j][1] 149 | variable_map_cnt += 1 150 | else: 151 | kn_pfn = val[0][1];#(d.get(cg_vpn))[1] 152 | 153 | if (kn_pfn == None): 154 | none_cnt += 1 155 | print(hex(cg_vpn), "what?") 156 | exit() 157 | else: 158 | paddr = kn_pfn * 4096 + cg_ofs 159 | mem_trace.write(elem[0] + " " + str(hex(paddr)) + "\n") 160 | ok_cnt += 1 161 | 162 | item_cnt += 1 163 | 164 | i += 1 165 | 166 | print("ok: %d, none: %d, (%.1f%%)" % (ok_cnt, none_cnt, (ok_cnt/(ok_cnt+none_cnt))*100.0)) 167 | mem_trace.seek(0) 168 | mem_trace.write(str(ok_cnt) + " " + str(none_cnt) + " " + str((ok_cnt/(ok_cnt+none_cnt))*100.0)) 169 | 170 | raw_trace_file.close() 171 | mem_trace.close() 172 | -------------------------------------------------------------------------------- /after_run/make_physical_trace_ts.py: -------------------------------------------------------------------------------- 1 | # If [.vout] trace file has timestamp, use this script. 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | import sys 5 | 6 | def file_len(fname): 7 | with open(fname) as f: 8 | for i, l in enumerate(f): 9 | pass 10 | return i + 1 11 | 12 | def find_close_mapping(x, a): 13 | target = 0 14 | close = 50 15 | small = 0 16 | big = len(a)-1 17 | for i in range(len(a)): 18 | if (a[i]) < x: 19 | small = i 20 | if a[i] >= x: 21 | big = i 22 | break 23 | diff_s = x-a[small] 24 | diff_b = a[big]-x 25 | 26 | if small == 0 and big == 0: 27 | target = small 28 | elif small == big and small > 0: 29 | target = big 30 | else: 31 | if diff_s < 0 or diff_b < 0: 32 | print("Error (diff_s: %d, diff_b: %d)" % (diff_s, diff_b)) 33 | elif diff_s < close and diff_b < close: 34 | target = small if diff_s <= diff_b else big 35 | elif diff_s < close: 36 | target = small 37 | elif diff_b < close: 38 | target = big 39 | return target 40 | 41 | 42 | 43 | input_file_name = sys.argv[1] 44 | linenum = file_len(input_file_name) 45 | print("linenum of %s: %d" % (input_file_name, linenum)) 46 | 47 | if input_file_name[-4:] != ".mix": 48 | print("input file [%s] is not .mix!" % (input_file_name)) 49 | exit() 50 | 51 | raw_trace_file = open(input_file_name, 'r') 52 | for i in range(7): 53 | line = raw_trace_file.readline() 54 | 55 | i = 0 56 | d = {} 57 | d.clear() 58 | item_idx = {} 59 | item_idx.clear() 60 | item_cnt = 0 61 | map_cnt = 0 62 | vpn_cnt = 0 63 | exist_cnt = 0 64 | 65 | # make v2p map (dictionary) 66 | while True: 67 | line = raw_trace_file.readline() 68 | if not line: break 69 | if (i % (linenum//1000)) == 0: 70 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 71 | 72 | num_cg = line.count('[') 73 | num_kn = line.count('{') 74 | num_total = num_cg + num_kn 75 | 76 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 77 | 78 | splitline = line.split("{") 79 | del splitline[0] 80 | 81 | for item in splitline: 82 | 83 | elem = item.split(" ") 84 | elem = ' '.join(elem).split() 85 | if elem[0] == 'R' or elem[0] == 'W': 86 | cg_vaddr = int(elem[1], 16) 87 | else: 88 | map_cnt += 1 89 | kn_vpn = int(elem[2], 16) 90 | kn_pfn = int(elem[3], 16) 91 | if kn_vpn in d: 92 | d[kn_vpn].append([item_cnt, kn_pfn]) 93 | exist_cnt += 1 94 | else: 95 | d[kn_vpn] = [[item_cnt, kn_pfn]] 96 | vpn_cnt += 1 97 | item_cnt += 1 98 | 99 | i += 1 100 | 101 | #raw_trace_file.close() 102 | 103 | 104 | 105 | # Second scan to translate Valgrind's virtual memory trace to the physical memory trace 106 | output_file_name = input_file_name[:-4] + ".pout" 107 | mem_trace = open(output_file_name, 'w') 108 | raw_trace_file.seek(0) 109 | 110 | for i in range(7): 111 | line = raw_trace_file.readline() 112 | 113 | i = 0 114 | item_cnt = 0 115 | none_cnt = 0 116 | ok_cnt = 0 117 | find_flag = 0 118 | variable_map_cnt = 0 119 | 120 | while True: 121 | line = raw_trace_file.readline() 122 | if not line: break 123 | if (i % (linenum//1000)) == 0: 124 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 125 | 126 | line = line.replace(']', '}').replace('[', '{').replace('}', ' ').replace('\n',' ') 127 | 128 | splitline = line.split("{") 129 | del splitline[0] 130 | 131 | for item in splitline: 132 | elem = item.split(" ") 133 | elem = ' '.join(elem).split() 134 | 135 | if elem[0] == 'R' or elem[0] == 'W': 136 | cg_vaddr = int(elem[1], 16) 137 | cg_vpn = cg_vaddr // 4096 138 | cg_ofs = cg_vaddr & 0xfff 139 | 140 | if (d.get(cg_vpn) == None): 141 | none_cnt += 1 142 | else: 143 | val = d[cg_vpn] 144 | if len(val) > 1: 145 | idx_list = [] 146 | for j in range(len(val)): 147 | idx_list.append(val[j][0]) 148 | target_j = find_close_mapping(item_cnt, idx_list) 149 | kn_pfn = val[target_j][1] 150 | variable_map_cnt += 1 151 | else: 152 | kn_pfn = val[0][1];#(d.get(cg_vpn))[1] 153 | 154 | if (kn_pfn == None): 155 | none_cnt += 1 156 | print(hex(cg_vpn), "what?") 157 | exit() 158 | else: 159 | paddr = kn_pfn * 4096 + cg_ofs 160 | mem_trace.write(elem[0] + " " + str(hex(paddr)) + " " + elem[2] + "\n") 161 | ok_cnt += 1 162 | 163 | item_cnt += 1 164 | 165 | i += 1 166 | 167 | print("ok: %d, none: %d, (%.1f%%)" % (ok_cnt, none_cnt, (ok_cnt/(ok_cnt+none_cnt))*100.0)) 168 | #mem_trace.seek(0) 169 | #mem_trace.write(str(ok_cnt) + " " + str(none_cnt) + " " + str((ok_cnt/(ok_cnt+none_cnt))*100.0)) 170 | 171 | raw_trace_file.close() 172 | mem_trace.close() 173 | -------------------------------------------------------------------------------- /after_run/mix_vpmap.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import sys 4 | 5 | def file_len(fname): 6 | with open(fname) as f: 7 | for i, l in enumerate(f): 8 | pass 9 | return i + 1 10 | 11 | input_file_name = sys.argv[1] 12 | if input_file_name[-5:] != ".vout": 13 | print("input file [%s] is not .vout!" % (input_file_name)) 14 | exit() 15 | linenum = file_len(input_file_name) 16 | print("linenum of %s: %d" % (input_file_name, linenum)) 17 | 18 | try: 19 | raw_trace_file = open(input_file_name, 'r') 20 | except: 21 | sys.stderr.write("No file: %s\n" % input_file_name) 22 | exit(1) 23 | 24 | for i in range(7): 25 | line = raw_trace_file.readline() 26 | 27 | vpmap_file_name = input_file_name[:-5] + ".vpmap" 28 | print("vpmap fname:", vpmap_file_name) 29 | 30 | try: 31 | vpmap_file = open(vpmap_file_name, 'r') 32 | except: 33 | sys.stderr.write("No file: %s\n" % vpmap_file_name) 34 | exit(1) 35 | 36 | output_file_name = input_file_name[:-5] + ".mix" 37 | mixed_file = open(output_file_name, 'w') 38 | 39 | i = 0 40 | vpmap_end = 0 41 | while True: 42 | line = raw_trace_file.readline() 43 | if not line: break 44 | if line[0] != "[": 45 | #print("[%d] %s" % (i, line), end="") 46 | i += 1 47 | continue 48 | #if line[0] == "=": break 49 | if (i % (linenum//1000)) == 0: 50 | print('\r', "%.0f%% [%d/%d]" % (i/linenum*100, i, linenum), end="") 51 | sline = line.replace(']', '').replace('\n', '') 52 | sline = sline.split(" ") 53 | #print("line:", line) 54 | #print("sline:", sline) 55 | #print(sline[-1]) 56 | ts = float(sline[-1]) 57 | #exit() 58 | 59 | # find earlier vpmap 60 | while vpmap_end == 0: 61 | ofs = vpmap_file.tell() 62 | mline = vpmap_file.readline() 63 | if not mline: 64 | vpmap_end = 1 65 | break 66 | msline = mline.replace('}', '').replace('\n', '') 67 | msline = msline.split(" ") 68 | map_ts = float(msline[-1]) 69 | if map_ts < ts: 70 | mixed_file.write(mline) 71 | else: 72 | vpmap_file.seek(ofs) 73 | break 74 | mixed_file.write(line) 75 | i += 1 76 | 77 | raw_trace_file.close() 78 | vpmap_file.close() 79 | mixed_file.close() 80 | 81 | -------------------------------------------------------------------------------- /run_script/README: -------------------------------------------------------------------------------- 1 | Use run_script.sh to start memory tracing. It generates virtual trace file with target executable program. 2 | It is a very simple script, so you can modify this script as you want. 3 | You can test the physical trace feature works well by running check.sh 4 | 5 | You can modify this script as you want. 6 | Line 58 and 63 is necessary. 7 | Line 58 runs valgrind to generate virtual memory address trace to the [.vout] file through stderr. 8 | and line 63 sends the pid of target process to the kernel. 9 | Upon receiving the target pid, the kernel outputs the VPN-PFN mapping information of the faulting address to the /proc/vpmap/vpmap. 10 | 11 | [How to use] 12 | ./run_script.sh --type [virtual/physical] --input [executable args..] 13 | NOTE: --input [] must be placed at the end of option 14 | Run [executable] with generating after-cache virtual address trace. 15 | virtual type: generate virtual address trace only. 16 | phyiscal type: generate virtual address trace & V2P mapping, and create physical address trace by mixing them. 17 | 18 | ./run_script.sh --type [virtual/physical] --pref --input [executable args..] 19 | NOTE: --input [] must be placed at the end of option 20 | Run [executable] with generating after-cache virtual address trace with cpu prefetcher in the valgrind cache simulator. 21 | To generate more accurate trace, recommend to use --pref option. 22 | 23 | Output: 24 | [trace_pref{ON/OFF}.vout] file: Virtual address trace 25 | [trace_pref{ON/OFF}.vpmap] file: V2P mapping information 26 | [trace_pref{ON/OFF}.mix] file: mixure of [.vout] and [.vpmap] following timestamps order 27 | [trace_pref{ON/OFF}.pout] file: Physical address trace 28 | [proclog.log] file: Redirection of process standard output 29 | [callgrind.out.#]: Output from vanilla Valgrind (We don't use. It's OK to remove these files) 30 | -------------------------------------------------------------------------------- /run_script/SeqW1G4K: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/run_script/SeqW1G4K -------------------------------------------------------------------------------- /run_script/check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cmd="./run_script.sh --input ./SeqW1G4K --type physical --pref" 4 | echo "\$$cmd" 5 | $cmd 6 | -------------------------------------------------------------------------------- /run_script/getopt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # options: 4 | INPUT_FILE="" 5 | OPT_INT=0 6 | OPT_BOOL=False 7 | INPUT_FILE_YES=0 8 | 9 | # get options: 10 | echo "Note: '--input [args]' must be placed at the end" 11 | while (( "$#" )); do 12 | case "$1" in 13 | -i|--input) 14 | if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then 15 | #INPUT_FILE=$2 16 | INPUT_FILE="${@:2}" 17 | INPUT_FILE_YES=1 18 | shift 2 19 | break 20 | else 21 | echo "Error: Argument for $1 is missing" >&2 22 | exit 1 23 | fi 24 | ;; 25 | -t|--type) 26 | if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then 27 | TRACE_TYPE=$2 28 | shift 2 29 | else 30 | echo "Error: Argument for $1 is missing" >&2 31 | exit 1 32 | fi 33 | ;; 34 | -o|--outname) 35 | if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then 36 | OUT_NAME=$2 37 | shift 2 38 | fi 39 | ;; 40 | -p|--pref) 41 | PREF=True 42 | shift 43 | ;; 44 | --nolog) 45 | NOLOG=True 46 | shift 47 | ;; 48 | -h|--help) 49 | echo "Usage: $0 -i [options]" >&2 50 | echo " -i | --input % (set input to ...)" >&2 51 | echo " -t | --type % (set trace type: virtual or physical)" >&2 52 | echo " -p | --pref (use cpu prefetcher in valgrind cache simulator)" >&2 53 | echo " --nolog (no redirection of standard output/error stream)" >&2 54 | exit 0 55 | ;; 56 | -*|--*) # unsupported flags 57 | echo "Error: Unsupported flag: $1" >&2 58 | echo "$0 -h for help message" >&2 59 | exit 1 60 | ;; 61 | *) 62 | echo "Error: Arguments with not proper flag: $1" >&2 63 | echo "$0 -h for help message" >&2 64 | exit 1 65 | ;; 66 | esac 67 | done 68 | echo "===parsed command line option===" 69 | echo " - input: ${INPUT_FILE}" 70 | echo " - type: ${TRACE_TYPE}" 71 | echo " - pref: ${PREF}" 72 | echo " - nolog: ${NOLOG}" 73 | -------------------------------------------------------------------------------- /run_script/run_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$EUID" -ne 0 ] 4 | then echo "Please run as root or with sudo privileges" 5 | exit 6 | fi 7 | 8 | # drop page caches 9 | sync 10 | echo 3 > /proc/sys/vm/drop_caches 11 | echo 1 > /proc/sys/vm/compact_memory 12 | echo 3 > /proc/sys/vm/drop_caches 13 | echo 1 > /proc/sys/vm/compact_memory 14 | 15 | tooldir=$(git rev-parse --show-toplevel) 16 | 17 | # command 18 | arguments=$@ 19 | . $tooldir/run_script/getopt.sh $arguments 20 | if [ $INPUT_FILE_YES -ne 1 ] || [ -z $TRACE_TYPE ]; then 21 | echo "No input or trace type!" 22 | echo " Args Example: -t/--type [virtual/physical] --pref -i/--input [\$INPUT_PROGRAM]" 23 | exit 24 | fi 25 | 26 | if [ "$TRACE_TYPE" == "virtual" ]; then 27 | echo "Trace type: Virtual address" 28 | echo "You can get trace file of Virtual address only" 29 | elif [ "$TRACE_TYPE" == "physical" ]; then 30 | echo "Trace type: Physical address" 31 | echo "You can get both trace files of Virtual address and V2P mapping. It requires modified kernel." 32 | echo 0 > /proc/vpmap/vpmap 33 | old_cg=$(pgrep -f callgrind | tail -n1) 34 | if [ -n "$old_cg" ]; then 35 | echo "[CAUTION] In the current version, only one process can be traced in the Physical Trace mode." 36 | echo "You should kill your old PIDs to run this script. The following PID list is assumed to be your old target processes:" 37 | old_cg_list=$(pgrep -f callgrind) 38 | echo "=========" 39 | echo "$old_cg_list" 40 | echo "=========" 41 | echo "Stop running.." 42 | exit 43 | fi 44 | fi 45 | 46 | if [ "$PREF" = True ]; then 47 | echo "Valgrind CPU Prefetch: ON" 48 | pref="yes" 49 | _pref="ON" 50 | else 51 | echo "Valgrind CPU Prefetch: OFF. Recommend using prefetch for more accurate trace.." 52 | pref="no" 53 | _pref="OFF" 54 | fi 55 | 56 | if [ -z "$OUT_NAME" ]; then 57 | logfile="trace_pref${_pref}" 58 | proclog="./proclog.log" 59 | else 60 | logfile="$OUT_NAME" 61 | proclog="./proclog_${OUT_NAME}.log" 62 | fi 63 | 64 | execname=$INPUT_FILE 65 | #proclog="./proclog.log" 66 | #logfile="trace_pref${_pref}" 67 | cglog="./$logfile.vout" 68 | 69 | if [ "$NOLOG" = True ]; then 70 | echo "NOLOG on!" 71 | proclog="" 72 | cglog="" 73 | fi 74 | 75 | start_time=`date +%s` 76 | 77 | # valgrind command 78 | echo "Run $execname with valgrind.." 79 | valgrind --tool=callgrind --simulate-wb=yes --simulate-hwpref=${pref} --log-fd=2 $execname > $proclog 2> $cglog & 80 | 81 | #target_pid=$(ps | grep callgrind | tail -n1 | awk '{print $1}') 82 | target_pid=$! 83 | pname=$(tr '\0' ' ' /sys/module/memory/parameters/target_pid 94 | echo $pidlist > /sys/module/memory/parameters/target_pid 95 | cat /sys/module/memory/parameters/target_pid 96 | fi 97 | 98 | while true; do 99 | if [ -d "/proc/$target_pid/" ]; then 100 | if [ "$TRACE_TYPE" == "physical" ]; then 101 | pidlist=$(ps -AL | grep callgrind | awk '{print $2}' | paste -s -d, -) # consider time lags of TIDs generation 102 | echo $pidlist > /sys/module/memory/parameters/target_pid 103 | fi 104 | sleep 0.3 105 | else 106 | break 107 | fi 108 | done 109 | 110 | wait $target_pid 111 | end_time=`date +%s` 112 | 113 | runtime=$((end_time-start_time)) 114 | echo "runtime: $runtime (sec)" 115 | 116 | if [ "$TRACE_TYPE" == "physical" ]; then 117 | cat /proc/vpmap/vpmap > ./$logfile.vpmap 118 | echo 0 > /sys/module/memory/parameters/target_pid 119 | fi 120 | 121 | echo "Process end" 122 | 123 | 124 | if [ "$TRACE_TYPE" == "physical" ]; then 125 | echo "Make physical trace using virtual trace and V2P mapping.." 126 | python3 $tooldir/after_run/mix_vpmap.py ./$logfile.vout 127 | python3 $tooldir/after_run/make_physical_trace_ts.py ./$logfile.mix 128 | nline_vout=$(wc -l ./$logfile.vout | awk '{print $1}') 129 | nline_pout=$(wc -l ./$logfile.pout | awk '{print $1}') 130 | echo "# of lines ([.vout] / [.pout]): $nline_vout / $nline_pout" 131 | rm ./$logfile.mix 132 | fi 133 | 134 | read -r -p "Do you want to plot graph? [y/N] " response 135 | if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]] 136 | then 137 | echo "plot virtual trace graph.." 138 | python3 $tooldir/after_run/graph/cg_histogram.py --input $logfile.vout --scatter 103 139 | if [ "$TRACE_TYPE" == "physical" ]; then 140 | echo "plot physical trace graph.." 141 | python3 $tooldir/after_run/graph/cg_pa_histogram.py --input $logfile.pout --scatter 103 142 | fi 143 | fi 144 | -------------------------------------------------------------------------------- /test/Synthetic_Workload/hashmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/test/Synthetic_Workload/hashmap -------------------------------------------------------------------------------- /test/Synthetic_Workload/hashmap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | #define NUM_OPS (1UL << 24) 6 | 7 | int main(){ 8 | 9 | unordered_map M; 10 | 11 | for(uint64_t i =0; i < NUM_OPS; i++){ 12 | M[i] =i; 13 | } 14 | 15 | 16 | for(auto i =0 ; i < M.bucket_count(); i++){ 17 | for(auto it = M.begin(i); it != M.end(i); it++){ 18 | auto temp {it->first}; 19 | auto temp2{it->second}; 20 | temp += temp2; 21 | } 22 | 23 | } 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/Synthetic_Workload/heap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/test/Synthetic_Workload/heap -------------------------------------------------------------------------------- /test/Synthetic_Workload/heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WORK_SIZE (1 << 27) //2G Bytes 7 | 8 | 9 | void add(uint64_t* h, uint64_t* lp, uint64_t value){ 10 | uint64_t insert_at = *lp +1; 11 | *lp = insert_at; 12 | h[insert_at] = value; 13 | 14 | uint64_t p = insert_at; 15 | 16 | while(p != 0){ 17 | uint64_t parent = (p -1)/2; 18 | 19 | if(h[parent] > h[p]){ 20 | uint8_t temp = h[p]; 21 | h[p] = h[parent]; 22 | h[parent] = temp; 23 | p = parent; 24 | }else{ 25 | return; 26 | } 27 | } 28 | } 29 | void delete(uint64_t* h, uint64_t* lp){ 30 | h[0] = h[*lp]; 31 | *lp = *lp -1; 32 | 33 | uint64_t p = 0; 34 | 35 | while(p <= *lp){ 36 | uint64_t lc =2*p +1; 37 | uint64_t rc =2*p +2; 38 | 39 | if(lc <= *lp){ 40 | if( lc!= *lp ){ 41 | uint64_t ep = 0; 42 | 43 | if(h[lc] > h[rc]) ep = rc; 44 | else ep = lc; 45 | 46 | if(h[p] > h[ep]){ 47 | int8_t temp = h[p]; 48 | h[p] = h[ep]; 49 | h[ep] = temp; 50 | p = ep; 51 | 52 | }else{ 53 | return; 54 | } 55 | 56 | }else{ 57 | if(h[p] > h[lc]){ 58 | uint8_t temp = h[p]; 59 | h[p] = h[lc]; 60 | h[lc] = temp; 61 | p = lc; 62 | } 63 | else{ 64 | return; 65 | } 66 | } 67 | 68 | }else{ 69 | return; 70 | } 71 | 72 | 73 | } 74 | 75 | 76 | } 77 | 78 | int main(){ 79 | uint64_t last_position = 0; 80 | 81 | uint64_t* h = (uint64_t*)malloc(sizeof(uint64_t)*WORK_SIZE); 82 | 83 | h[0] = (uint64_t)rand()+1; 84 | 85 | 86 | for(uint64_t i = 0; i < WORK_SIZE -1 ; i++){ 87 | if (i % (1<<15) == 1){ 88 | delete(h, &last_position); 89 | } 90 | add(h, &last_position, (uint64_t)rand()+1); 91 | //printf("%lu ", last_position); 92 | } 93 | 94 | // for(uint64_t i = 0; i < WORK_SIZE ; i++){ 95 | // printf("%lu ", h[i]); 96 | // } 97 | 98 | 99 | return 0; 100 | } -------------------------------------------------------------------------------- /test/Synthetic_Workload/indirect_delta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/test/Synthetic_Workload/indirect_delta -------------------------------------------------------------------------------- /test/Synthetic_Workload/indirect_delta.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define ROW_SIZE (4UL) 5 | #define COL_SIZE (4UL) 6 | 7 | #define WORK_SET (1UL << 22) 8 | 9 | 10 | int main(){ 11 | 12 | uint8_t*** ALL = (uint8_t***) malloc(WORK_SET*sizeof(uint8_t**)); 13 | 14 | for(uint64_t ops =0; ops < WORK_SET; ops++){ 15 | 16 | 17 | uint8_t** M = (uint8_t**)malloc(ROW_SIZE*sizeof(uint8_t*)); 18 | 19 | for(uint64_t i =0; i < ROW_SIZE; i++){ 20 | M[i] = (uint8_t*)malloc(COL_SIZE*sizeof(uint8_t)); 21 | } 22 | ALL[ops] = M; 23 | 24 | } 25 | 26 | for(uint64_t ops = 0 ; ops < WORK_SET - 3; ops += 3){ 27 | uint8_t** M = ALL[ops]; 28 | uint8_t** M2 = ALL[ops+1]; 29 | uint8_t**M3 = ALL[ops+2]; 30 | 31 | for(uint64_t i =0; i < ROW_SIZE; i++){ 32 | for(uint64_t j = 0; j < COL_SIZE; j++){ 33 | for(uint64_t k =0; k < ROW_SIZE; k++){ 34 | M3[i][j] = M[i][k] * M2[k][j]; 35 | } 36 | } 37 | } 38 | } 39 | 40 | 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/Synthetic_Workload/strided_latjob: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/test/Synthetic_Workload/strided_latjob -------------------------------------------------------------------------------- /test/Synthetic_Workload/strided_latjob.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WORK_SIZE (1L << 33) //1G Bytes 7 | #define ACCESS_SIZE 64L //64 Bytes 8 | #define STRIDE_SIZE (64L*16) //64 Bytes 9 | #define ACCESS_COUNT (WORK_SIZE/STRIDE_SIZE) 10 | 11 | 12 | int main(){ 13 | uint64_t count = 0; 14 | 15 | uint8_t *addr = (uint8_t*)malloc((WORK_SIZE)*sizeof(uint8_t)); 16 | memset(addr, 1, WORK_SIZE * sizeof(uint8_t)); 17 | while(count != ACCESS_COUNT){ 18 | 19 | for(uint16_t i = 0; i < ACCESS_SIZE; i ++){ 20 | addr[i] = addr[i] + 1; 21 | } 22 | 23 | 24 | addr += STRIDE_SIZE; 25 | 26 | count++; 27 | } 28 | 29 | 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /test/Synthetic_Workload/true_random: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgist-datalab/trace_generator/42d8f70135bb91b266229eb3247e20955762a2be/test/Synthetic_Workload/true_random -------------------------------------------------------------------------------- /test/Synthetic_Workload/true_random.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define WORK_SIZE (1L << 32) //1G Bytes 7 | #define ACCESS_SIZE 64L //64 Bytes 8 | #define STRIDE_SIZE (64L*4) //64 Bytes 9 | #define ACCESS_COUNT (WORK_SIZE/STRIDE_SIZE) 10 | 11 | 12 | int main(){ 13 | uint64_t count = 0; 14 | 15 | uint8_t *addr = (uint8_t*)malloc((WORK_SIZE)*sizeof(uint8_t)); 16 | memset(addr, 1, WORK_SIZE * sizeof(uint8_t)); 17 | while(count != ACCESS_COUNT){ 18 | 19 | uint64_t index = rand()%32768 + (rand()%( WORK_SIZE/32768)) * (32768); 20 | addr[index] +=1; 21 | 22 | count++; 23 | } 24 | 25 | 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /test/test_synthetic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$EUID" -ne 0 ] 4 | then echo "Please run as root or with sudo privileges" 5 | exit 6 | fi 7 | 8 | tool_dir=$(git rev-parse --show-toplevel) 9 | run_script="${tool_dir}/run_script/run_script.sh" 10 | synth_dir="${tool_dir}/test/Synthetic_Workload" 11 | 12 | options=("indirect_delta" "true_random" "heap" "strided_latjob" "hashmap") 13 | 14 | echo "Please select a synthetic workload to test: " 15 | PS3="Input workload number: " 16 | 17 | select opt in "${options[@]}"; do 18 | case $opt in 19 | "indirect_delta") 20 | echo "You chose $opt" 21 | break 22 | ;; 23 | "true_random") 24 | echo "You chose $opt" 25 | break 26 | ;; 27 | "heap") 28 | echo "You chose $opt" 29 | break 30 | ;; 31 | "strided_latjob") 32 | echo "You chose $opt" 33 | break 34 | ;; 35 | "hashmap") 36 | echo "You chose $opt" 37 | break 38 | ;; 39 | *) echo "Invalid option $REPLY";; 40 | esac 41 | done 42 | 43 | response="" 44 | while [[ ! "$response" =~ ^([vVpP])$ ]]; do 45 | read -r -p "Get only virtual address trace or both virtual/physical address trace? [v/p] " response 46 | if [[ "$response" =~ ^([vV])$ ]]; then 47 | trace_type="virutal" 48 | elif [[ "$response" =~ ^([pP])$ ]]; then 49 | trace_type="physical" 50 | else 51 | echo "Invalid option: $response. Please enter 'v' or 'p'." 52 | fi 53 | done 54 | echo "selected trace type: $trace_type" 55 | 56 | tname="$opt" 57 | tpath="${synth_dir}/$tname" 58 | 59 | cmd="${run_script} --type $trace_type --pref --outname $tname --input $tpath" 60 | 61 | echo "\$$cmd" 62 | $cmd 63 | --------------------------------------------------------------------------------