Created
March 20, 2020 04:41
-
-
Save emfomenk/bc1a8752e31defe9999ee36c4d89150d to your computer and use it in GitHub Desktop.
Play with uninitialized memory
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _XOPEN_SOURCE 700 | |
#include <sys/types.h> | |
#include <fcntl.h> /* open */ | |
#include <stdint.h> /* uint64_t */ | |
#include <stdio.h> /* printf */ | |
#include <stdlib.h> /* size_t */ | |
#include <unistd.h> /* pread, sysconf */ | |
#include <sys/mman.h> | |
#include <malloc.h> | |
#include <iostream> | |
#include <chrono> | |
#include <cmath> | |
#include "dnnl.hpp" | |
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr); | |
template<typename T> | |
void init_random(int size, T* ptr) { | |
for (int i=0; i<size; ++i) | |
ptr[i] = static_cast<T>(127.0f*static_cast<float>(rand()) / static_cast <float> (RAND_MAX)); | |
} | |
template<typename T> | |
void init_zero(int size, T* ptr) { | |
for (int i=0; i<size; ++i) | |
ptr[i] = static_cast<T>(0); | |
} | |
void *my_malloc(size_t size) { | |
return memalign(4*1024, size); | |
} | |
int main() { | |
int m = 10; | |
int n = 3072; | |
int k = 768; | |
int iters = 1000; | |
char trans_a = 'N'; | |
char trans_b = 'N'; | |
char offsetc = 'F'; | |
float alpha = 1.0f; | |
int lda = k; | |
uint8_t ao = 0; | |
int ldb = n; | |
int8_t bo = 0; | |
float beta = 0.0f; | |
int ldc = n; | |
std::array<int32_t, 1> oc = {0}; | |
pid_t pid = getpid(); | |
void* weights_p = my_malloc(k*n*sizeof(int8_t)); | |
int8_t* weights = static_cast<int8_t*>(weights_p); | |
// mlock(weights, k*n*sizeof(int8_t)); | |
void* input_p = my_malloc(m*k*sizeof(uint8_t)); | |
uint8_t* input = static_cast<uint8_t*>(input_p); | |
init_random(m*k, input); | |
void* output_p = my_malloc(m*n*sizeof(int)); | |
int* output = static_cast<int*>(output_p); | |
auto bench = [&](const char *str) { | |
float total=0.0f; | |
int dryrun=3; | |
for (int i=0; i<iters; ++i) { | |
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); | |
dnnl_gemm_u8s8s32(trans_a, trans_b, offsetc, | |
m, n, k, alpha, const_cast<const uint8_t*>(input), lda, ao, | |
const_cast<const int8_t*>(weights), ldb, bo, | |
beta, output, ldc, oc.data()); | |
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); | |
if (i>=dryrun) | |
total += std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count(); | |
} | |
float time = total/(iters-dryrun); | |
printf("%s memory: %g ms. Physical addresses: ", str, time); | |
for (auto *p = weights; p < weights + k * n; p += 4096 / sizeof(*weights)) { | |
void *phys; | |
virt_to_phys_user((uintptr_t *)&phys, pid, (uintptr_t)p); | |
printf("%p ", phys); | |
} | |
printf("\n"); | |
}; | |
bench("Uninitialized"); | |
init_zero(k*n, weights); | |
bench("Initialized"); | |
return 0; | |
} | |
// source: https://stackoverflow.com/a/45128487 | |
typedef struct { | |
uint64_t pfn : 54; | |
unsigned int soft_dirty : 1; | |
unsigned int file_page : 1; | |
unsigned int swapped : 1; | |
unsigned int present : 1; | |
} PagemapEntry; | |
/* Parse the pagemap entry for the given virtual address. | |
* | |
* @param[out] entry the parsed entry | |
* @param[in] pagemap_fd file descriptor to an open /proc/pid/pagemap file | |
* @param[in] vaddr virtual address to get entry for | |
* @return 0 for success, 1 for failure | |
*/ | |
int pagemap_get_entry(PagemapEntry *entry, int pagemap_fd, uintptr_t vaddr) | |
{ | |
size_t nread; | |
ssize_t ret; | |
uint64_t data; | |
uintptr_t vpn; | |
vpn = vaddr / sysconf(_SC_PAGE_SIZE); | |
nread = 0; | |
while (nread < sizeof(data)) { | |
ret = pread(pagemap_fd, &data, sizeof(data) - nread, | |
vpn * sizeof(data) + nread); | |
nread += ret; | |
if (ret <= 0) { | |
return 1; | |
} | |
} | |
entry->pfn = data & (((uint64_t)1 << 54) - 1); | |
entry->soft_dirty = (data >> 54) & 1; | |
entry->file_page = (data >> 61) & 1; | |
entry->swapped = (data >> 62) & 1; | |
entry->present = (data >> 63) & 1; | |
return 0; | |
} | |
/* Convert the given virtual address to physical using /proc/PID/pagemap. | |
* | |
* @param[out] paddr physical address | |
* @param[in] pid process to convert for | |
* @param[in] vaddr virtual address to get entry for | |
* @return 0 for success, 1 for failure | |
*/ | |
int virt_to_phys_user(uintptr_t *paddr, pid_t pid, uintptr_t vaddr) | |
{ | |
char pagemap_file[BUFSIZ]; | |
int pagemap_fd; | |
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid); | |
pagemap_fd = open(pagemap_file, O_RDONLY); | |
if (pagemap_fd < 0) { | |
return 1; | |
} | |
PagemapEntry entry; | |
if (pagemap_get_entry(&entry, pagemap_fd, vaddr)) { | |
return 1; | |
} | |
close(pagemap_fd); | |
*paddr = (entry.pfn * sysconf(_SC_PAGE_SIZE)) + (vaddr % sysconf(_SC_PAGE_SIZE)); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment