-
-
Save yodamaster/37cd2e09b68cd3e38da4823d5bf2a1ed to your computer and use it in GitHub Desktop.
Revisions
-
larytet revised this gist
Jul 13, 2017 . 1 changed file with 0 additions and 172 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -385,177 +385,5 @@ static void hashtable_close(hashtable_t *hashtable) } \ -
larytet revised this gist
Jul 13, 2017 . 2 changed files with 561 additions and 303 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,303 +0,0 @@ This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,561 @@ /** * Lockfree is a set of lockfree containers for Linux and Linux kernel * Copyright (C) <2017> Arkady Miasnikov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Implementation of lockfree linear probing hashtable * The hashtable targets SystemTap environment where a typical key is thread ID * The number of probes is limited by a constant. The index is not wrapping around, * but instead the hashtable allocates enough memory to handle linear probing in the end * of the table * * Limitation: a specific entry (a specific key) can be inserted and deleted by one thread. * * Performance: a core can make above 13M add&remove operations per second, cost of a * single operation is under 20nano which is an equivalent of 50-100 opcodes. */ #pragma once #ifdef __KERNEL__ # include "linux/vmalloc.h" # include "linux/printk.h" # define DEV_NAME "lockless" # define PRINTF(s, ...) printk(KERN_ALERT DEV_NAME ": %s: " s "\n", __func__, __VA_ARGS__) # define PRIu64 "llu" #else # include <stdlib.h> # include <stdio.h> # include <inttypes.h> # define PRINTF(s, ...) printf("%s: " s "\n", __func__, __VA_ARGS__) # define likely(x) __builtin_expect(!!(x), 1) // !!(x) will return 1 for any x != 0 # define unlikely(x) __builtin_expect(!!(x), 0) # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #define __sync_access(x) (*(volatile __typeof__(*x) *) (x)) /** * Based on https://gist.github.com/badboy/6267743 * http://burtleburtle.net/bob/hash/integer.html * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ static uint32_t hash32shift(uint32_t key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 187; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } static uint32_t hash_none(uint32_t key) { return key; } typedef struct { uint64_t insert; uint64_t remove; uint64_t search; uint64_t collision; uint64_t insert_err; uint64_t remove_err; } hashtable_stat_t; typedef struct { const char *name; size_t bits; uint32_t (*hashfunction)(uint32_t); size_t __size; size_t __memory_size; hashtable_stat_t __stat; void *__table; } hashtable_t; static hashtable_t *hashtable_registry[64]; static int hashtable_show(char *buf, size_t len) { size_t i; int rc; size_t chars = 0; rc = snprintf(buf+chars, len-chars, "\n%-25s %12s %12s %12s %12s %12s %12s %12s %12s %12s \n", "Name", "Size", "Memory", "Ops", "Insert", "Remove", "Search", "Collision", "InsertErr", "RemoveErr"); chars += rc; for (i = 0;i < ARRAY_SIZE(hashtable_registry);i++) { hashtable_t *hashtable = hashtable_registry[i]; hashtable_stat_t *stat; if (!hashtable) continue; stat = &hashtable->__stat; rc = snprintf(buf+chars, len-chars, "%-25s %12zu %12zu %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 " %12" PRIu64 "\n", hashtable->name, hashtable->__size, hashtable->__memory_size, stat->insert+stat->remove+stat->search, stat->insert, stat->remove, stat->search, stat->collision, stat->insert_err, stat->remove_err ); chars += rc; } return chars; } static void hashtable_registry_add(hashtable_t *table) { size_t i; for (i = 0;i < ARRAY_SIZE(hashtable_registry);i++) { hashtable_t *registry = hashtable_registry[i]; if (registry == table) { PRINTF("Hashtable %s already registered", table->name); break; } if (!registry) { PRINTF("Register hashtable %s", table->name); hashtable_registry[i] = table; break; } } } static void hashtable_registry_remove(hashtable_t *table) { size_t i; for (i = 0;i < ARRAY_SIZE(hashtable_registry);i++) { hashtable_t *registry = hashtable_registry[i]; if (registry == table) { PRINTF("Remove hashtable %s from the registry", table->name); hashtable_registry[i] = NULL; } } } static inline size_t hashtable_get_index(const hashtable_t *hashtable, const uint32_t hash) \ { \ return hash & (hashtable->__size - 1); \ } \ static void *hashtable_alloc(size_t size) { #ifdef __KERNEL__ void *p; size = PAGE_ALIGN(size); p = vmalloc(size); if (p) { unsigned long long adr = (unsigned long long) p; while (size > 0) { SetPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } } return p; #else return malloc(size); #endif } static void hashtable_free(void *p, size_t size) { #ifdef __KERNEL__ if (p) { unsigned long long adr = (unsigned long long) p; while ((long) size > 0) { ClearPageReserved(vmalloc_to_page((void *)adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; } vfree(p); } #else free(p); #endif } static void hashtable_close(hashtable_t *hashtable) { if (hashtable->__table) { hashtable_free(hashtable->__table, hashtable->__memory_size); } else { PRINTF("Failed to free null pointer for the hashtable %s", hashtable->name); } hashtable_registry_remove(hashtable); } #ifdef __KERNEL__ # define HASHTABLE_CMPXCHG(key, val, new_val) cmpxchg(key, val, new_val) #else # define HASHTABLE_CMPXCHG(key, val, new_val) __sync_val_compare_and_swap(key, val, new_val) #endif #if 1 #ifdef __KERNEL__ # define HASHTABLE_BARRIER() barrier() #else # define HASHTABLE_BARRIER() __sync_synchronize() #endif #else # define HASHTABLE_BARRIER() #endif #define HASHTABLE_SLOT_ADDR(hashtable, tokn, index) &(((hashtable_## tokn ##_slot_t*)hashtable->__table)[index]) /** * Illegal TID can be (PID_MAX_LIMIT+1) * Illegal data is 0 for TID, -1 for FD, etc (this is optional) */ #define DECLARE_HASHTABLE(tokn, data_type, max_tries, illegal_key, illegal_data) \ \ typedef struct \ { \ volatile uint32_t key; \ data_type data; \ } hashtable_## tokn ## _slot_t; \ \ static void hashtable_## tokn ## _init_slot(hashtable_## tokn ## _slot_t *slot) \ { \ slot->key = illegal_key; \ slot->data = illegal_data; \ } \ \ /** \ * Calculate number of slots in the hash table \ * I add max_tries on top to ensure that there are max_tries slots after the \ * end of the table \ */ \ static size_t hashtable_## tokn ##_memory_size(const int bits) \ { \ size_t slots = (1 << bits) + max_tries; \ return (sizeof(hashtable_## tokn ## _slot_t) * slots); \ } \ \ static int hashtable_## tokn ##_init(hashtable_t *hashtable) \ { \ size_t memory_size = hashtable_## tokn ## _memory_size(hashtable->bits); \ void *p = hashtable_alloc(memory_size); \ size_t i; \ if (p) \ { \ if (hashtable->hashfunction == NULL) \ { \ hashtable->hashfunction = hash32shift; \ } \ hashtable->__size = (1 << hashtable->bits); \ hashtable->__memory_size = memory_size; \ hashtable->__table = p; \ for (i = 0;i < hashtable->__size;i++) \ { \ hashtable_## tokn ## _init_slot(HASHTABLE_SLOT_ADDR(hashtable, tokn, i)); \ } \ hashtable_registry_add(hashtable); \ return 1; \ } \ PRINTF("Failed to allocate %zu for the hashtable %s", memory_size, hashtable->name); \ return 0; \ } \ \ /** \ * Hash the key, get an index in the hashtable, try compare-and-set. \ * If fails (not likely) try again with the next slot (linear probing) \ * continue until success or max_tries is hit \ */ \ static int hashtable_## tokn ##_insert(hashtable_t *hashtable, const uint32_t key, const data_type data) \ { \ const uint32_t hash = hashtable->hashfunction(key); \ const uint32_t index = hashtable_get_index(hashtable, hash); \ /* I can do this for the last slot too - I allocated max_tries more slots */ \ const uint32_t index_max = index+max_tries; \ uint32_t i; \ hashtable->__stat.insert++; \ for (i = index;i < index_max;i++) \ { \ hashtable_## tokn ##_slot_t *slot = HASHTABLE_SLOT_ADDR(hashtable, tokn, i); \ uint32_t old_key = HASHTABLE_CMPXCHG(&slot->key, illegal_key, key); \ if (likely(old_key == illegal_key)) /* Success */ \ { \ slot->data = data; \ return 1; \ } \ else \ { \ hashtable->__stat.collision++; \ } \ } \ \ hashtable->__stat.insert_err++; \ return 0; \ } \ \ /** \ * Hash the key, get an index in the hashtable, find the relevant entry, \ * read the pointer, remove using atomic operation \ * Only one context is allowed to remove a specific entry \ */ \ static int hashtable_## tokn ##_remove(hashtable_t *hashtable, const uint32_t key, data_type *data) \ { \ const uint32_t hash = hashtable->hashfunction(key); \ const uint32_t index = hashtable_get_index(hashtable, hash); \ /* I can do this for the last slot too - I allocated max_tries more slots */ \ const uint32_t index_max = index+max_tries; \ uint32_t i; \ hashtable->__stat.remove++; \ for (i = index;i < index_max;i++) \ { \ hashtable_## tokn ##_slot_t *slot = HASHTABLE_SLOT_ADDR(hashtable, tokn, i); \ uint32_t old_key = slot->key; \ if (likely(old_key == key)) \ { \ if (data) \ { \ *data = slot->data; \ } \ __sync_access(&slot->data) = illegal_data; \ HASHTABLE_BARRIER(); \ __sync_access(&slot->key) = illegal_key; \ return 1; \ } \ } \ \ hashtable->__stat.remove_err++; \ return 0; \ } \ \ /** \ * Hash the key, get an index in the hashtable, find the relevant entry, \ * read the pointer \ */ \ static int hashtable_## tokn ##_find(hashtable_t *hashtable, const uint32_t key, data_type *data) \ { \ const uint32_t hash = hashtable->hashfunction(key); \ const uint32_t index = hashtable_get_index(hashtable, hash); \ /* I can do this for the last slot too - I allocated max_tries more slots */ \ const uint32_t index_max = index+max_tries; \ uint32_t i; \ hashtable->__stat.search++; \ for (i = index;i < index_max;i++) \ { \ hashtable_## tokn ##_slot_t *slot = HASHTABLE_SLOT_ADDR(hashtable, tokn, i); \ uint32_t old_key = slot->key; \ if (old_key == key) \ { \ *data = slot->data; \ return 1; \ } \ } \ \ return 0; \ } \ #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include "hashtable.h" #include "linux_utils.h" #define HASHTABLE_BITS 8 static hashtable_t hashtable = {"hash", HASHTABLE_BITS, hash_none}; DECLARE_HASHTABLE(uint32, uint32_t, 4, 0, 0); /** * The hashtable does 'value & ((1 << HASHTABLE_BITS)-1)' * The function generates values which will cause collision * in the table slot 0, the values are unique */ static inline uint32_t get_value_collision(int idx) { return ((1 << HASHTABLE_BITS) << idx); } static inline uint32_t get_value(int idx) { return idx; } static int thread_job(void *thread_arg) { int idx = (int)(size_t)thread_arg; uint32_t value_to_store = get_value(idx); while (1) { int rc = hashtable_uint32_insert(&hashtable, value_to_store, 0); if (!rc) { linux_log(LINUX_LOG_ERROR, "Thread %d failed to insert entry %u", idx, value_to_store); return 1; } rc = hashtable_uint32_remove(&hashtable, value_to_store, NULL); if (!rc) { linux_log(LINUX_LOG_ERROR, "Thread %d failed to remove entry %u", idx, value_to_store); return 1; } } return 1; } static int create_threads(int cpus) { int rc; for (int i = 0;i < cpus;i++) { linux_task_state_t *state = (linux_task_state_t*)calloc(1, sizeof(linux_task_state_t)); char filename[64]; sprintf(filename, "%d", i); state->properties.name = strdup(filename); state->properties.task = thread_job; state->properties.task_arg = (void*)(size_t)i; rc = linux_thread_start(state); if (!rc) { break; } } return rc; } static int synchronous_access(int cpus) { for (int i = 0;i < cpus;i++) { uint32_t value_to_store = get_value(i); int rc = hashtable_uint32_insert(&hashtable, value_to_store, 0); if (!rc) { linux_log(LINUX_LOG_ERROR, "Thread %d failed to insert entry %u", i, value_to_store); return 0; } } for (int i = 0;i < cpus;i++) { uint32_t value_to_store = get_value(i); int rc = hashtable_uint32_remove(&hashtable, value_to_store, NULL); if (!rc) { linux_log(LINUX_LOG_ERROR, "Thread %d failed to remove entry %u", i, value_to_store); return 0; } } return 1; } int main() { int cpus = 4; //linux_get_number_processors() int rc; do { rc = hashtable_uint32_init(&hashtable); if (!rc) { break; } rc = synchronous_access(cpus); if (!rc) { break; } rc = create_threads(cpus); if (!rc) { break; } while (1) { linux_ms_sleep(1000); char buf[4*1024]; hashtable_show(buf, ARRAY_SIZE(buf)); linux_log(LINUX_LOG_INFO, "%s", buf); } hashtable_close(&hashtable); } while (0); return 0; } =========== Makefile ============ TARGET = hashtable_test CXXFLAGS = -O2 -g -Wall -fmessage-length=0 -std=c++11 CXX = $(CROSS)g++ $(INCLUDE_DIRS) LIBS = -lpthread -lrt APP_OBJS = ./hashtable_test.o \ ./linux_utils.o \ APP_DEPS = ./hashtable_test.cpp \ ./linux_utils.cpp \ ./linux_utils.h \ ./Makefile \ ./hashtable.h \ $(TARGET):: $(APP_DEPS) $(APP_OBJS) $(CXX) $(CXXFLAGS) -o $(TARGET) -pthread $(APP_OBJS) $(LIBS) all: $(TARGET) clean: $(Q)rm -f $(APP_OBJS) $(TARGET) -
larytet revised this gist
Jul 12, 2017 . 1 changed file with 212 additions and 137 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,53 @@ /** * Lockfree is a set of lockfree containers for Linux and Linux kernel * Copyright (C) <2017> Arkady Miasnikov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Implementation of lockfree linear probing hashtable * The hashtable targets SystemTap environment where a typical key is thread ID * The number of probes is limited by a constant. The index is not wrapping around, * but instead the hashtable allocates enough memory to handle linear probing in the end * of the table * * Limitation: a specific entry (a specific key) can be inserted and deleted by one thread. * * Performance: a core can make above 13M add&remove operations per second, cost of a * single operation is under 20nano which is an equivalent of 50-100 opcodes. */ #pragma once #if KERNEL # inclide "linux/vmalloc.h" # include "linux/printk.h" # define DEV_NAME "lockless" # define PRINTF(s, ...) printk(KERN_ALERT DEV_NAME ": %s: " s "\n", __func__, __VA_ARGS__) #else # include <stdlib.h> # include <stdio.h> # define PRINTF(s, ...) printf("%s: " s "\n", __func__, __VA_ARGS__) # define likely(x) __builtin_expect(!!(x), 1) // !!(x) will return 1 for any x != 0 # define unlikely(x) __builtin_expect(!!(x), 0) #endif #define __sync_access(x) (*(volatile __typeof__(*x) *) (x)) /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory @@ -6,33 +56,33 @@ */ typedef struct { volatile uint32_t key; uint32_t age; void *data; } hashtable_slot_t; typedef struct { size_t size; uint64_t insert; uint64_t remove; uint64_t collision; uint64_t insert_err; uint64_t remove_err; } hashtable_stat_t; typedef struct { const char *name; size_t bits; // Probably not necessary, because I am going to use a trivial one to one hash function uint32_t (*hashfunction)(uint32_t); size_t __size; size_t __memory_size; hashtable_slot_t *__table; hashtable_stat_t __stat; } hashtable_t; @@ -43,13 +93,13 @@ typedef struct */ static size_t hashtable_memory_size(const int bits, size_t max_tries) { size_t slots = (1 << bits) + max_tries; return (sizeof(hashtable_slot_t) * slots); } static const size_t HASHTABLE_MAX_TRIES = 8; // Illegal TID can be (PID_MAX_LIMIT+1) static const uint32_t ILLEGAL_KEY = 0; /** * Based on https://gist.github.com/badboy/6267743 @@ -58,171 +108,196 @@ static const u32 ILLEGAL_KEY = 0; * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ static uint32_t hash32shift(uint32_t key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 187; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } static uint32_t hash_none(uint32_t key) { return key; } static void hashtable_init_slot(hashtable_slot_t *slot) { slot->key = ILLEGAL_KEY; slot->data = NULL; slot->age = 0; } static int hashtable_init(hashtable_t *hashtable) { size_t memory_size = hashtable_memory_size(hashtable->bits, HASHTABLE_MAX_TRIES); #ifdef KERNEL void *p = vmalloc(memory_size); #else void *p = malloc(memory_size); #endif size_t i; if (p) { if (hashtable->hashfunction == NULL) { hashtable->hashfunction = hash32shift; } hashtable->__size = (1 << hashtable->bits); hashtable->__memory_size = memory_size; hashtable->__table = (hashtable_slot_t*)p; for (i = 0;i < hashtable->__size;i++) { hashtable_init_slot(&hashtable->__table[i]); } return 1; } PRINTF("Failed to allocate %u for the hashtable %s", (unsigned)memory_size, hashtable->name); return 0; } static int hashtable_init_all(hashtable_t *hashtable) { int res = 0; for (;hashtable->name && hashtable->bits;hashtable++) { res = hashtable_init(hashtable); if (!res) break; } return res; } static void hashtable_close(hashtable_t *hashtable) { if (hashtable->__table) { #ifdef KERNEL vfree(hashtable->__table); #else free(hashtable->__table); #endif } else { PRINTF("Failed to free null pointer for the hashtable %s", hashtable->name); } } static void hashtable_close_all(hashtable_t *hashtable) { for (;hashtable->name && hashtable->bits;hashtable++) { hashtable_close(hashtable); } } static inline size_t hashtable_get_index(const hashtable_t *hashtable, const uint32_t hash) { return hash & (hashtable->__size - 1); } /** * Hash the key, get an index in the hashtable, try compare-and-set. * If fails (not likely) try again with the next slot (linear probing) * continue until success or max_tries is hit */ static int hashtable_insert(hashtable_t *hashtable, const uint32_t key, void * const data) { const uint32_t hash = hashtable->hashfunction(key); const uint32_t index = hashtable_get_index(hashtable, hash); const uint32_t index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots uint32_t i; hashtable->__stat.insert++; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[i]; #if KERNEL uint32_t old_key = cmpxchg(&slot->key, ILLEGAL_KEY, key); #else uint32_t old_key = __sync_val_compare_and_swap(&slot->key, ILLEGAL_KEY, key); #endif if (likely(old_key == ILLEGAL_KEY)) // Success { slot->data = data; return 1; } else { hashtable->__stat.collision++; } } hashtable->__stat.insert_err++; return 0; } /** * Hash the key, get an index in the hashtable, find the relevant entry, * read the pointer, remove using atomic operation * Only one context is allowed to remove a specific entry */ static int hashtable_remove(hashtable_t *hashtable, const uint32_t key, void **data) { const uint32_t hash = hashtable->hashfunction(key); const uint32_t index = hashtable_get_index(hashtable, hash); const uint32_t index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots uint32_t i; hashtable->__stat.remove++; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[i]; uint32_t old_key = slot->key; if (likely(old_key == key)) { if (data) { *data = slot->data; } __sync_access(&slot->data) = NULL; #if 0 // I hope that I do not need a barrier here #ifdef KERNEL barrier(); #else __sync_synchronize(); #endif #endif __sync_access(&slot->key) = ILLEGAL_KEY; return 1; } } hashtable->__stat.remove_err++; return 0; } /** * Hash the key, get an index in the hashtable, find the relevant entry, * read the pointer */ static int hashtable_find(const hashtable_t *hashtable, const uint32_t key, void **data) { const uint32_t hash = hashtable->hashfunction(key); const uint32_t index = hashtable_get_index(hashtable, hash); const uint32_t index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots uint32_t i; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[i]; uint32_t old_key = slot->key; if (old_key == key) { *data = slot->data; return 1; } } return 0; } -
larytet revised this gist
Jul 9, 2017 . 1 changed file with 0 additions and 22 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,25 +1,3 @@ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory -
larytet revised this gist
Jul 9, 2017 . 1 changed file with 130 additions and 46 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,25 @@ /** * Based on https://gist.github.com/larytet/c306d470f7b032c796efad15dcd609a9 */ /** * YALAS is a Linux audit system based on SystemTap * Copyright (C) <2017> Arkady Miasnikov * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory @@ -14,8 +36,25 @@ typedef struct typedef struct { size_t size; u64 insert; u64 remove; u64 collision; u64 insert_err; u64 remove_err; } hashtable_stat_t; typedef struct { const char *name; size_t bits; // Probably not necessary, because I am going to use a trivial one to one hash function u32 (*hashfunction)(u32); size_t __size; size_t __memory_size; hashtable_slot_t *__table; hashtable_stat_t __stat; } hashtable_t; @@ -34,57 +73,95 @@ static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; /** * Based on https://gist.github.com/badboy/6267743 * http://burtleburtle.net/bob/hash/integer.html * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ static u32 hash32shift(u32 key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 187; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } static u32 hash_none(u32 key) { return key; } static void hashtable_init_slot(hashtable_slot_t *slot) { slot->key = ILLEGAL_KEY; slot->data = NULL; slot->age = 0; } static int hashtable_init(hashtable_t *hashtable) { size_t memory_size = hashtable_memory_size(hashtable->bits, HASHTABLE_MAX_TRIES); void *p = vmalloc(memory_size); int i; if (p) { if (hashtable->hashfunction == NULL) { hashtable->hashfunction = hash32shift; } hashtable->__size = (1 << hashtable->bits); hashtable->__memory_size = memory_size; memset(&hashtable->__stat, 0, sizeof(hashtable->__stat)); hashtable->__table = (hashtable_slot_t*)p; for (i = 0;i < hashtable->__size;i++) { hashtable_init_slot(&hashtable->__table[i]); } return 1; } PRINTF("Failed to allocate %u for the hashtable %s", (unsigned)memory_size, hashtable->name); return 0; } static int hashtable_init_all(hashtable_t *hashtable) { int res = 0; for (;hashtable->name && hashtable->bits;hashtable++) { res = hashtable_init(hashtable); if (!res) break; } return res; } static void hashtable_close(hashtable_t *hashtable) { if (hashtable->__table) { vfree(hashtable->__table); } else { PRINTF("Failed to free null pointer for the hashtable %s", hashtable->name); } } static void hashtable_close_all(hashtable_t *hashtable) { for (;hashtable->name && hashtable->bits;hashtable++) { hashtable_close(hashtable); } } /** @@ -94,22 +171,28 @@ static u32 hash32shift(u32 key) */ static int hashtable_insert(hashtable_t *hashtable, const u32 key, void * const data) { const u32 hash = hashtable->hashfunction(key); const u32 index = hash & hashtable->__size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; hashtable->__stat.insert++; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[index]; u32 old_key = cmpxchg(&slot->key, ILLEGAL_KEY, key); if (old_key == ILLEGAL_KEY) // Success { slot->data = data; return 1; } else { hashtable->__stat.collision++; } } hashtable->__stat.insert_err++; return 0; } /** @@ -119,25 +202,27 @@ static int hashtable_insert(hashtable_t *hashtable, const u32 key, void * const */ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hashtable->hashfunction(key); const u32 index = hash & hashtable->__size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; hashtable->__stat.remove++; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[index]; u32 old_key = slot->key; if (old_key == key) { *data = slot->data; slot->data = NULL; barrier(); slot->key = ILLEGAL_KEY; return 1; } } hashtable->__stat.remove_err++; return 0; } /** @@ -146,21 +231,20 @@ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) */ static int hashtable_find(const hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hashtable->hashfunction(key); const u32 index = hash & hashtable->__size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->__table[index]; u32 old_key = slot->key; if (old_key == key) { *data = slot->data; return 1; } } return 0; } -
larytet revised this gist
Jul 9, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -73,6 +73,7 @@ static void hashtable_close(hashtable_t *hashtable) * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers * TODO For TID I can use a trivial hash function - 22 bits is an equivalent of ~64MB in the RAM */ static u32 hash32shift(u32 key) { -
larytet revised this gist
Jul 8, 2017 . 1 changed file with 23 additions and 68 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -26,74 +26,23 @@ typedef struct */ static size_t hashtable_memory_size(const int bits, size_t max_tries) { size_t slots = (1 << bits) + max_tries; return (sizeof(hashtable_slot_t) * slots); } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; static void hashtable_init_slot(hashtable_slot_t *slot) { slot->key = ILLEGAL_KEY; slot->data = NULL; slot->age = 0; } static int hashtable_init(hashtable_t *hashtable, const size_t bits) { size_t memory_size = hashtable_memory_size(bits, HASHTABLE_MAX_TRIES); @@ -113,14 +62,19 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) return 1; } static void hashtable_close(hashtable_t *hashtable) { vfree(hashtable->table); } /** * Based on https://gist.github.com/badboy/6267743 * http://burtleburtle.net/bob/hash/integer.html * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ static u32 hash32shift(u32 key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; @@ -137,19 +91,19 @@ public u32 hash32shift(u32 key) * If fails (not likely) try again with the next slot (linear probing) * continue until success or max_tries is hit */ static int hashtable_insert(hashtable_t *hashtable, const u32 key, void * const data) { const u32 hash = hash32shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->table[index]; u32 old_key = cmpxchg(&slot->key, ILLEGAL_KEY, key); if (old_key == ILLEGAL_KEY) // Success { slot->data = data; return 0; } } @@ -170,14 +124,14 @@ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) u32 i; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->table[index]; u32 old_key = slot->key; if (old_key == key) { *data = slot->data; slot->data = NULL; barrier(); slot->key = ILLEGAL_KEY; return 0; } } @@ -197,14 +151,15 @@ static int hashtable_find(const hashtable_t *hashtable, const u32 key, void **da u32 i; for (i = index;i < index_max;i++) { hashtable_slot_t *slot = &hashtable->table[index]; u32 old_key = slot->key; if (old_key == key) { *data = slot->data; return 0; } } return 1; } -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 2 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -114,7 +114,8 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) } /** * Based on https://gist.github.com/badboy/6267743 * http://burtleburtle.net/bob/hash/integer.html * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory * Th field age is a timestamp in ms when the slot * is populated. */ typedef struct -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,7 +1,7 @@ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory * Th field age is a timestamp in microseconds when the slot * is populated. */ typedef struct -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -103,11 +103,11 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) { hashtable->size = (1 << bits); hashtable->memory_size = memory_size; hashtable->table = (hashtable_slot_t*)p; for (i = 0;i < hashtable->size;i++) { hashtable_init_slot(&hashtable->table[i]); } return 0; } return 1; -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -105,7 +105,7 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) hashtable->memory_size = memory_size; for (i = 0;i < hashtable->size;i++) { hashtable_init_slot(&hashtable->table[i]); } hashtable->table = (hashtable_slot_t*)p; return 0; -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 65 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -21,7 +21,7 @@ typedef struct /** * Calculate number of slots in the hash table * I add max_tries on top to ensure that there are max_tries slots after the * end of the table */ static size_t hashtable_memory_size(const int bits, size_t max_tries) @@ -30,7 +30,7 @@ static size_t hashtable_memory_size(const int bits, size_t max_tries) } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { @@ -53,24 +53,84 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) return 1; } /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory * Th field age is a value of the CPU cycles counter when the slot * is populated. */ typedef struct { volatile u32 key; u32 age; void *data; } hashtable_slot_t; typedef struct { size_t size; size_t memory_size; hashtable_slot_t *table; } hashtable_t; /** * Calculate number of slots in the hash table * I add max_tries on top to ensure that there are max_tries slots after the * end of the table */ static size_t hashtable_memory_size(const int bits, size_t max_tries) { return (sizeof(hashtable_slot_t) * ((1 << bits) + max_tries); } static void hashtable_init_slot(hashtable_slot_t *slot) { slot->key = ILLEGAL_KEY; slot->data = NULL; slot->age = 0; } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { size_t memory_size = hashtable_memory_size(bits, HASHTABLE_MAX_TRIES); void *p = vmalloc(memory_size); int i; if (p) { hashtable->size = (1 << bits); hashtable->memory_size = memory_size; for (i = 0;i < hashtable->size;i++) { hashtable_init_slot(&hashtable->tale[i]); } hashtable->table = (hashtable_slot_t*)p; return 0; } return 1; } /** * Based on https://gist.github.com/badboy/6267743 * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ public u32 hash32shift(u32 key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 187; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } /** * Hash the key, get an index in the hashtable, try compare-and-set. * If fails (not likely) try again with the next slot (linear probing) @@ -147,4 +207,3 @@ static int hashtable_find(const hashtable_t *hashtable, const u32 key, void **da return 1; } -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -66,7 +66,7 @@ public u32 hash32shift(u32 key) key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 187; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 6 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -57,16 +57,17 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) * Based on https://gist.github.com/badboy/6267743 * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts * I adopt the hash function for 22 (PID_MAX_LIMIT) bits integers */ public u32 hash32shift(u32 key) { key = ~key + (key << 10); // key = (key << 15) - key - 1; key = key ^ (key >> 7); key = key + (key << 1); key = key ^ (key >> 2); key = key * 2057; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 11); return key; } -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,8 @@ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory * Th field age is a value of the CPU cycles counter when the slot * is populated. */ typedef struct { -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -5,6 +5,7 @@ typedef struct { volatile u32 key; u32 age; void *data; } hashtable_slot_t; @@ -42,6 +43,7 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) { hashtable->tale[i].key = ILLEGAL_KEY; hashtable->tale[i].data = NULL; hashtable->tale[i].age = 0; } hashtable->table = (hashtable_slot_t*)p; return 0; -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -81,7 +81,7 @@ static int hashtable_insert(hashtable_t *hashtable, const u32 key, const void *d { u32 *slot_key = (u32*)&hashtable->table[index]; u32 old_key = cmpxchg(slot_key, ILLEGAL_KEY, key); if (old_key == ILLEGAL_KEY) // Success { slot_key->data = data; return 0; -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 13 additions and 12 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -54,25 +54,26 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts */ public u32 hash32shift(u32 key) { key = ~key + (key << 15); // key = (key << 15) - key - 1; key = key ^ (key >> 12); key = key + (key << 2); key = key ^ (key >> 4); key = key * 2057; // key = (key + (key << 3)) + (key << 11); key = key ^ (key >> 16); return key; } /** * Hash the key, get an index in the hashtable, try compare-and-set. * If fails (not likely) try again with the next slot (linear probing) * continue until success or max_tries is hit */ static int hashtable_insert(hashtable_t *hashtable, const u32 key, const void *data) { const u32 hash = hash32shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; @@ -97,7 +98,7 @@ static int hashtable_insert(hashtable_t *hashtable, const u32 key, const void *d */ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hash32shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; @@ -124,7 +125,7 @@ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) */ static int hashtable_find(const hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hash32shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -27,7 +27,7 @@ static size_t hashtable_memory_size(const int bits, size_t max_tries) } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -27,7 +27,7 @@ static size_t hashtable_memory_size(const int bits, size_t max_tries) } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can (PID_MAX_LIMIT+1) static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -27,6 +27,7 @@ static size_t hashtable_memory_size(const int bits, size_t max_tries) } static const size_t HASHTABLE_MAX_TRIES = 3; // Illegal TID can be (1<<23) static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,5 @@ /** * My key is a thread ID (22 bits) and my data is a chunk in the * FIFO orgtanised in the driver shared memory */ typedef struct -
larytet revised this gist
Jul 6, 2017 . 1 changed file with 8 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,3 +1,7 @@ /** * My key is thread ID and my data is a chunk in the * FIFO orgtanised in the driver shared memory */ typedef struct { volatile u32 key; @@ -14,7 +18,8 @@ typedef struct /** * Calculate number of slots in the hash table * I add max_tries on top to ensure that there are max_tries slots after the * end of the table */ static size_t hashtable_memory_size(const int bits, size_t max_tries) { @@ -45,8 +50,8 @@ static int hashtable_init(hashtable_t *hashtable, const size_t bits) /** * Based on https://gist.github.com/badboy/6267743 * I replace the 'long key' by 'unsigned key' and unsigned Java right shifts * by regular C/C++ right shifts */ public u32 hash6432shift(u64 key) { -
larytet created this gist
Jul 5, 2017 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,138 @@ typedef struct { volatile u32 key; void *data; } hashtable_slot_t; typedef struct { size_t size; size_t memory_size; hashtable_slot_t *table; } hashtable_t; /** * Calculate number of slots in the hash table * I add max_tries on top to ensure that there are max_tries slots in the end of the table */ static size_t hashtable_memory_size(const int bits, size_t max_tries) { return (sizeof(hashtable_slot_t) * ((1 << bits) + max_tries); } static const size_t HASHTABLE_MAX_TRIES = 3; static const u32 ILLEGAL_KEY = 0; static int hashtable_init(hashtable_t *hashtable, const size_t bits) { size_t memory_size = hashtable_memory_size(bits, HASHTABLE_MAX_TRIES); void *p = vmalloc(memory_size); int i; if (p) { hashtable->size = (1 << bits); hashtable->memory_size = memory_size; for (i = 0;i < hashtable->size;i++) { hashtable->tale[i].key = ILLEGAL_KEY; hashtable->tale[i].data = NULL; } hashtable->table = (hashtable_slot_t*)p; return 0; } return 1; } /** * Based on https://gist.github.com/badboy/6267743 * I replace the 'long key' by 'unsigned key' and unsigned Java shifts right * by regular C/C++ shifts right */ public u32 hash6432shift(u64 key) { key = (~key) + (key << 18); // key = (key << 18) - key - 1; key = key ^ (key >> 31); key = key * 21; // key = (key + (key << 2)) + (key << 4); key = key ^ (key >> 11); key = key + (key << 6); key = key ^ (key >> 22); return (u32)key; } /** * Hash the key, get an index in the hashtable, try compare-and-set. * If fails (not likely) try again with the next slot (linear probing) * continue until success or max_tries is hit */ static int hashtable_insert(hashtable_t *hashtable, const u32 key, const void *data) { const u32 hash = hash6432shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; for (i = index;i < index_max;i++) { u32 *slot_key = (u32*)&hashtable->table[index]; u32 old_key = cmpxchg(slot_key, ILLEGAL_KEY, key); if (old_key == ILLEGAL_KEY) { slot_key->data = data; return 0; } } return 1; } /** * Hash the key, get an index in the hashtable, find the relevant entry, * read the pointer, remove using atomic operation * Only one context is allowed to remove a specific entry */ static int hashtable_remove(hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hash6432shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; for (i = index;i < index_max;i++) { u32 *slot_key = (u32*)&hashtable->table[index]; u32 old_key = slot_key->key; if (old_key == key) { *data = slot_key->data; slot_key->data = NULL; barrier(); slot_key->key = ILLEGAL_KEY; return 0; } } return 1; } /** * Hash the key, get an index in the hashtable, find the relevant entry, * read the pointer */ static int hashtable_find(const hashtable_t *hashtable, const u32 key, void **data) { const u32 hash = hash6432shift(key); const u32 index = hash & hashtable->size; const u32 index_max = index+HASHTABLE_MAX_TRIES; // I can do this for the last slot too - I allocated max_tries more slots u32 i; for (i = index;i < index_max;i++) { u32 *slot_key = (u32*)&hashtable->table[index]; u32 old_key = slot_key->key; if (old_key == key) { *data = slot_key->data; return 0; } } return 1; }