├── Makefile ├── README.md ├── build ├── app │ ├── hashmap │ └── hashmap.map └── hashmap.map ├── err.log ├── include ├── shm_bucket.h ├── shm_common.h ├── shm_hash_fun.h ├── shm_hash_map.h ├── shm_hash_table.h ├── shm_node_pool.h ├── shm_profiler.h ├── shm_stl_config.h ├── test.h └── test │ ├── Makefile │ ├── main.cpp │ ├── main.o │ └── test ├── main.cpp └── mk ├── internal └── rte.compile-pre.mk └── toolchain └── gcc └── rte.vars.mk /Makefile: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ifeq ($(RTE_SDK),) 33 | $(error "Please define RTE_SDK environment variable") 34 | endif 35 | 36 | # Default target, can be overriden by command line or environment 37 | RTE_TARGET ?= x86_64-default-linuxapp-gcc 38 | 39 | include $(RTE_SDK)/mk/rte.vars.mk 40 | 41 | # binary name 42 | APP = hashmap 43 | 44 | # all source are stored in SRCS-y 45 | SRCS-y := main.cpp 46 | 47 | INCDIR = /home/jwli/dpdk-1.6.0r2/examples/multi_process/hashmap/ 48 | 49 | CFLAGS += -O3 50 | CFLAGS += -I$(INCDIR) 51 | WERROR_FLAGS += -Wno-unused-result -Wno-unused-function 52 | CFLAGS += $(WERROR_FLAGS) 53 | 54 | include $(RTE_SDK)/mk/rte.extapp.mk 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | more-effective-dpdk-share-hashmap 2 | ================================= 3 | 4 | An effective share hashmap based on dpdk 5 | --- 6 | This is an implementation of share hash_map based on dpdk. Dpdk lib implements a hash table named rte_hash itself. 7 | But it is difficult to use and lack of extensibility. So I write this hash_map. It is as convenience as std::hash_map 8 | and could be shared by multi process. 9 | 10 | Major Features 11 | --- 12 | 1. Based on DPDK library 13 | 2. Could be shared by multi process 14 | 3. It is an template container, could hold arbitrary value type 15 | 4. It looks like std::hash_map, you can define your own hasher and key_equal functor 16 | 5. It can expand its size automatically 17 | 18 | Build 19 | --- 20 | 1. Download the source codes of dpdk from dpdk.org 21 | 2. Read the intel-dpdk-getting-start-guide.pdf to learn how to set up a dpdk develop environment 22 | 3. Build and run the helloworld example in dpdk-1.6.0r2/examples/ 23 | 4. Copy the files under hashmap/mk/ to dpdk-1.6.0r2/mk/ to enable g++ for dpdk 24 | 5. Build this program by following command: 25 | $ make CC=g++ 26 | 27 | Run 28 | --- 29 | 1. Make sure you have run dpdk-1.6.0r2/tools/setup.sh to set up your dpdk running environment 30 | >< You would know what I mean if you have run the helloworld program > 31 | 32 | 2. Start the primary process 33 | >$ sudo ./build/hashmap -c 1 -n 4 --proc-type=primary 34 | 35 | 3. Start the secondary process 36 | >$ sudo ./build/hashmap -c c -n 4 --proc-type=secondary 37 | 38 | Any issue, you can contact with me by email 39 | -------------------------------------------------------------------------------- /build/app/hashmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiangwlee/more-effective-dpdk-share-hashmap/c68896e357780783bbf8ca104165de92424e2d42/build/app/hashmap -------------------------------------------------------------------------------- /err.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiangwlee/more-effective-dpdk-share-hashmap/c68896e357780783bbf8ca104165de92424e2d42/err.log -------------------------------------------------------------------------------- /include/shm_bucket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation; either version 2 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, see . 14 | * 15 | * Copyright (C) Bruce.Li , 2014 16 | */ 17 | 18 | 19 | #ifndef __SHM_BUCKET_H_ 20 | #define __SHM_BUCKET_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "shm_node_pool.h" 28 | #include "shm_profiler.h" 29 | 30 | using std::ostream; 31 | 32 | __SHM_STL_BEGIN 33 | 34 | const u_int32_t DEFAULT_BUCKET_NUM = 4096; 35 | const u_int32_t ENTRIES_PER_BUCKET = 16; 36 | 37 | template 38 | class Bucket { 39 | public: 40 | typedef _Node node_t; 41 | typedef _Key key_t; 42 | typedef _Value value_t; 43 | typedef NodePool node_pool_t; 44 | 45 | public: 46 | Bucket (uint32 pool_size = ENTRIES_PER_BUCKET) 47 | : m_node_pool(pool_size), m_size(0), m_head(NULL){ 48 | rte_rwlock_init(&m_lock); 49 | } 50 | ~Bucket () {} 51 | 52 | uint32 capacity(void) const {return m_node_pool.capacity();} 53 | uint32 free_entries(void) const {return m_node_pool.free_entries();} 54 | 55 | void clear(void) { 56 | if (m_head == NULL) { 57 | m_size = 0; 58 | return; 59 | } 60 | 61 | rte_rwlock_write_lock(&m_lock); 62 | 63 | // return nodes to node pool 64 | node_t* end = m_head; 65 | while (end->next()) 66 | end = end->next(); 67 | 68 | m_node_pool.put_nodelist(m_head, end, m_size); 69 | 70 | m_size = 0; 71 | m_head = NULL; 72 | 73 | rte_rwlock_write_unlock(&m_lock); 74 | return; 75 | } 76 | 77 | // Put a node at the head of this bucket 78 | bool put(const sig_t &signature, const key_t &key, const value_t &value) { 79 | bool ret = true; 80 | node_t * node = NULL; 81 | 82 | rte_rwlock_write_lock(&m_lock); 83 | 84 | // check if this key is already in this bucket 85 | if (find_node(signature, key)) { 86 | ret = false; 87 | goto exit; 88 | } 89 | 90 | node = m_node_pool.get_node(); 91 | if (node == NULL) { 92 | ret = false; 93 | goto exit; 94 | } 95 | node->fill(key, value, signature); 96 | node->set_next(m_head); 97 | m_head = node; 98 | ++m_size; 99 | 100 | exit: 101 | rte_rwlock_write_unlock(&m_lock); 102 | return ret; 103 | } 104 | 105 | // Lookup a node by signature and key 106 | bool lookup(const sig_t &sig, const key_t &key, value_t * ret) { 107 | rte_rwlock_read_lock(&m_lock); 108 | 109 | node_t* node = find_node(sig, key); 110 | if (node && ret) *ret = node->value(); 111 | 112 | rte_rwlock_read_unlock(&m_lock); 113 | 114 | if (node) 115 | return true; 116 | else 117 | return false; 118 | } 119 | 120 | // Remove a node from this bucket 121 | bool remove(const sig_t &sig, const key_t &key, value_t * ret) { 122 | rte_rwlock_write_lock(&m_lock); 123 | 124 | node_t * node = find_node(sig, key); 125 | 126 | // If we find this node, now it is in the front of our node list, 127 | // we just remove it from the head 128 | if (node) { 129 | if (ret) 130 | *ret = node->value(); 131 | 132 | m_head = node->next(); 133 | node->set_next(NULL); 134 | --m_size; 135 | 136 | // put this node back to node_pool 137 | m_node_pool.put_node(node); 138 | } 139 | 140 | rte_rwlock_write_unlock(&m_lock); 141 | 142 | if (node) 143 | return true; 144 | else 145 | return false; 146 | } 147 | 148 | // update a node in this bucket 149 | template 150 | bool update(const sig_t &sig, const key_t &key, _Params ¶ms, _Modifier &action) { 151 | rte_rwlock_write_lock(&m_lock); 152 | 153 | bool ret = false; 154 | node_t * node = find_node(sig, key); 155 | 156 | // If we find this node, update it! 157 | if (node) { 158 | node->update(params, action); 159 | ret = true; 160 | } 161 | 162 | rte_rwlock_write_unlock(&m_lock); 163 | return ret; 164 | } 165 | 166 | uint32 size(void) const {return m_size;} 167 | 168 | void str(ostream &os) const { 169 | os << "\nBucket Size : " << m_size << std::endl; 170 | node_t* curr = m_head; 171 | while (curr) { 172 | curr->str(os); 173 | curr = curr->next(); 174 | } 175 | } 176 | 177 | private: 178 | node_t * find_node(const sig_t &sig, const key_t &key) const { 179 | // Search in this bucket 180 | node_t * current = m_head; 181 | while (current) { 182 | if (sig == current->signature() && m_equal_to(key, current->key())) { 183 | break; 184 | } 185 | 186 | current = current->next(); 187 | } 188 | 189 | return current; 190 | } 191 | 192 | public: 193 | node_pool_t m_node_pool; 194 | volatile uint32 m_size; // the size of this bucket 195 | node_t * volatile m_head; // the pointer of the first node in this bucket 196 | _KeyEqual m_equal_to; 197 | rte_rwlock_t m_lock; 198 | }; 199 | 200 | __SHM_STL_END 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /include/shm_common.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHM_COMMON_H_ 2 | #define __SHM_COMMON_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "shm_stl_config.h" 8 | 9 | __SHM_STL_BEGIN 10 | 11 | static inline bool 12 | is_power_of_2(u_int32_t num) { 13 | return (num & (num - 1)) == 0; 14 | } 15 | 16 | /* convert to a number to power of 2 which is greater than it 17 | * For example, convert 3 to power of 2, the result is 4 18 | */ 19 | static inline u_int32_t 20 | convert_to_power_of_2(u_int32_t num) { 21 | u_int32_t bits = 0; 22 | while (num) { 23 | ++bits; 24 | num >>= 1; 25 | } 26 | 27 | // bits should not exceed 31 28 | if (bits >= sizeof(num) * 8) 29 | bits = sizeof(num) * 8 - 1; 30 | 31 | return (bits == 0) ? 0 : 1 << bits; 32 | } 33 | 34 | /* Does integer division with rounding-up of result. */ 35 | inline u_int32_t 36 | div_roundup(u_int32_t numerator, u_int32_t denominator) 37 | { 38 | return (numerator + denominator - 1) / denominator; 39 | } 40 | 41 | /* Increases a size (if needed) to a multiple of alignment. */ 42 | inline u_int32_t 43 | align_size(u_int32_t val, u_int32_t alignment) 44 | { 45 | return alignment * div_roundup(val, alignment); 46 | } 47 | 48 | __SHM_STL_END 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/shm_hash_fun.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996-1998 3 | * Silicon Graphics Computer Systems, Inc. 4 | * 5 | * Permission to use, copy, modify, distribute and sell this software 6 | * and its documentation for any purpose is hereby granted without fee, 7 | * provided that the above copyright notice appear in all copies and 8 | * that both that copyright notice and this permission notice appear 9 | * in supporting documentation. Silicon Graphics makes no 10 | * representations about the suitability of this software for any 11 | * purpose. It is provided "as is" without express or implied warranty. 12 | * 13 | * 14 | * Copyright (c) 1994 15 | * Hewlett-Packard Company 16 | * 17 | * Permission to use, copy, modify, distribute and sell this software 18 | * and its documentation for any purpose is hereby granted without fee, 19 | * provided that the above copyright notice appear in all copies and 20 | * that both that copyright notice and this permission notice appear 21 | * in supporting documentation. Hewlett-Packard Company makes no 22 | * representations about the suitability of this software for any 23 | * purpose. It is provided "as is" without express or implied warranty. 24 | * 25 | */ 26 | 27 | /* NOTE: This is an internal header file, included by other STL headers. 28 | * You should not attempt to use it directly. 29 | */ 30 | 31 | #ifndef __SHM_STL_HASH_FUN_H 32 | #define __SHM_STL_HASH_FUN_H 33 | 34 | #include 35 | #include 36 | #include "shm_stl_config.h" 37 | 38 | __SHM_STL_BEGIN 39 | 40 | template struct hash { 41 | size_t operator() (const _Key &key) const { 42 | return rte_jhash(&key, sizeof(key), 0); 43 | } 44 | }; 45 | 46 | inline size_t __stl_hash_string(const char* __s) 47 | { 48 | unsigned long __h = 0; 49 | for ( ; *__s; ++__s) 50 | __h = 5*__h + *__s; 51 | 52 | return size_t(__h); 53 | } 54 | 55 | __SHM_STL_TEMPLATE_NULL struct hash 56 | { 57 | size_t operator()(const char* __s) const { return __stl_hash_string(__s); } 58 | }; 59 | 60 | __SHM_STL_TEMPLATE_NULL struct hash 61 | { 62 | size_t operator()(const char* __s) const { return __stl_hash_string(__s); } 63 | }; 64 | 65 | __SHM_STL_TEMPLATE_NULL struct hash { 66 | size_t operator()(char __x) const { return __x; } 67 | }; 68 | __SHM_STL_TEMPLATE_NULL struct hash { 69 | size_t operator()(unsigned char __x) const { return __x; } 70 | }; 71 | __SHM_STL_TEMPLATE_NULL struct hash { 72 | size_t operator()(unsigned char __x) const { return __x; } 73 | }; 74 | __SHM_STL_TEMPLATE_NULL struct hash { 75 | size_t operator()(short __x) const { return __x; } 76 | }; 77 | __SHM_STL_TEMPLATE_NULL struct hash { 78 | size_t operator()(unsigned short __x) const { return __x; } 79 | }; 80 | __SHM_STL_TEMPLATE_NULL struct hash { 81 | size_t operator()(int __x) const { return __x; } 82 | }; 83 | __SHM_STL_TEMPLATE_NULL struct hash { 84 | size_t operator()(unsigned int __x) const { return __x; } 85 | }; 86 | __SHM_STL_TEMPLATE_NULL struct hash { 87 | size_t operator()(long __x) const { return __x; } 88 | }; 89 | __SHM_STL_TEMPLATE_NULL struct hash { 90 | size_t operator()(unsigned long __x) const { return __x; } 91 | }; 92 | 93 | __SHM_STL_END 94 | 95 | #endif /* __SGI_STL_HASH_FUN_H */ 96 | 97 | // Local Variables: 98 | // mode:C++ 99 | // End: 100 | -------------------------------------------------------------------------------- /include/shm_hash_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * return m_ht->find(key, ret); 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, see . 15 | * 16 | * Copyright (C) Bruce.Li , 2014 17 | */ 18 | 19 | 20 | #ifndef __SHM_HASH_MAP_H_ 21 | #define __SHM_HASH_MAP_H_ 22 | 23 | #include "shm_hash_table.h" 24 | #include "shm_profiler.h" 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #define RETURN_FALSE_IF_NULL(ptr) do {\ 36 | if (ptr == NULL) return false;\ 37 | } while (0) 38 | 39 | #define SHM_NAME_SIZE 32 40 | 41 | __SHM_STL_BEGIN 42 | 43 | template , typename _EqualKey = std::equal_to<_Key> > 44 | class hash_map { 45 | public: 46 | typedef _Key key_type; 47 | typedef _Value value_type; 48 | typedef _HashFunc hasher; 49 | typedef _EqualKey key_equal; 50 | typedef hash_table _Ht; 51 | 52 | public: 53 | hash_map(const char * name, uint32 buckets = DEFAULT_BUCKET_NUM): m_buckets(buckets) { 54 | snprintf(m_name, sizeof(m_name), "HT_%s", name); 55 | } 56 | 57 | ~hash_map() { 58 | if (rte_eal_process_type() == RTE_PROC_PRIMARY) 59 | m_ht->~_Ht(); 60 | 61 | m_ht = NULL; 62 | } 63 | 64 | bool create_or_attach(void) { 65 | uint32 shm_size = sizeof(_Ht); 66 | const rte_proc_type_t proc_type = rte_eal_process_type(); 67 | 68 | if (proc_type == RTE_PROC_PRIMARY) { 69 | const struct rte_memzone * zone = rte_memzone_reserve(&m_name[0], shm_size, 0, 70 | RTE_MEMZONE_SIZE_HINT_ONLY); 71 | // replacement new, call the constructor of hash table 72 | m_ht = ::new (zone->addr) _Ht(m_buckets); 73 | } else if (proc_type == RTE_PROC_SECONDARY) { 74 | const struct rte_memzone * zone = rte_memzone_lookup(&m_name[0]); 75 | m_ht = static_cast<_Ht*>(zone->addr); 76 | } else { 77 | m_ht = NULL; 78 | } 79 | 80 | if (m_ht) { 81 | return true; 82 | } else { 83 | return false; 84 | } 85 | } 86 | 87 | 88 | bool find(const key_type &key, value_type * ret = NULL) { 89 | RETURN_FALSE_IF_NULL(m_ht); 90 | return m_ht->find(key, ret); 91 | } 92 | 93 | bool insert(const key_type &key, const value_type &value) { 94 | RETURN_FALSE_IF_NULL(m_ht); 95 | return m_ht->insert(key, value); 96 | } 97 | 98 | bool erase(const key_type &key, value_type * ret = NULL) { 99 | RETURN_FALSE_IF_NULL(m_ht); 100 | return m_ht->erase(key, ret); 101 | } 102 | 103 | template 104 | bool update(const key_type &key, _Params params, _Modifier &update) { 105 | RETURN_FALSE_IF_NULL(m_ht); 106 | return m_ht->update(key, params, update); 107 | } 108 | 109 | void clear(void) { 110 | if (m_ht) m_ht->clear(); 111 | } 112 | 113 | void print(void) { 114 | std::ostringstream os; 115 | if (m_ht) { 116 | m_ht->str(os); 117 | } else { 118 | os << "Hash table is not created!" << std::endl; 119 | } 120 | 121 | std::cout << os.str().c_str() << std::endl; 122 | } 123 | 124 | uint32 capacity(void) const { 125 | if (m_ht) 126 | return m_ht->capacity(); 127 | else 128 | return 0; 129 | } 130 | 131 | uint32 free_entries(void) const { 132 | if (m_ht) 133 | return m_ht->free_entries(); 134 | else 135 | return 0; 136 | } 137 | 138 | uint32 used_entries(void) const { 139 | if (m_ht) 140 | return m_ht->used_entries(); 141 | else 142 | return 0; 143 | } 144 | 145 | private: 146 | uint32 m_buckets; 147 | char m_name[SHM_NAME_SIZE]; 148 | _Ht * m_ht; 149 | }; 150 | 151 | #undef SHM_NAME_SIZE 152 | 153 | __SHM_STL_END 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /include/shm_hash_table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This program is free software; you can redistribute it and/or modify 3 | * it under the terms of the GNU General Public License as published by 4 | * the Free Software Foundation; either version 2 of the License, or 5 | * (at your option) any later version. 6 | * 7 | * This program is distributed in the hope that it will be useful, 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | * GNU General Public License for more details. 11 | * 12 | * You should have received a copy of the GNU General Public License 13 | * along with this program; if not, see . 14 | * 15 | * Copyright (C) Bruce.Li , 2014 16 | */ 17 | 18 | 19 | #ifndef __SHM_HASH_TABLE_H_ 20 | #define __SHM_HASH_TABLE_H_ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "shm_hash_fun.h" 30 | #include "shm_common.h" 31 | #include "shm_bucket.h" 32 | 33 | using std::ostream; 34 | 35 | __SHM_STL_BEGIN 36 | 37 | template 38 | struct Assignment { 39 | void operator() (volatile _Value &old_value, const _Value &new_value) { 40 | old_value = new_value; 41 | } 42 | }; 43 | 44 | template , typename _EqualKey = std::equal_to<_Key> > 45 | class hash_table { 46 | public: 47 | typedef Node<_Key, _Value> node_type; 48 | typedef _Key key_type; 49 | typedef _Value value_type; 50 | typedef _HashFunc hasher; 51 | typedef _EqualKey key_equal; 52 | typedef NodePool node_pool_t; 53 | typedef Bucket bucket_type; 54 | 55 | public: 56 | hash_table(uint32 buckets = DEFAULT_BUCKET_NUM) 57 | : m_mask(0), m_bucket_num(buckets), m_bucket_array(NULL) { 58 | initialize(); 59 | } 60 | 61 | ~hash_table(void) {finalize();} 62 | 63 | bool insert(const key_type & key, const value_type & value) { 64 | sig_t sig = m_hash_func(key); 65 | bucket_type * bucket = get_bucket_by_sig(sig); 66 | 67 | // Put node to bucket 68 | return bucket->put(sig, key, value); 69 | } 70 | 71 | /* 72 | * @brief 73 | * This method takes two parameters : 74 | * key is an input parameter for hash table lookup 75 | * ret is an output parameter to take the value if the key is in the hash table 76 | * */ 77 | bool find(const key_type & key, value_type * ret = NULL) const { 78 | // Get bucket 79 | sig_t sig = m_hash_func(key); 80 | bucket_type * bucket = get_bucket_by_sig(sig); 81 | 82 | // Search in this bucket 83 | return bucket->lookup(sig, key, ret); 84 | } 85 | 86 | bool erase(const key_type &key, value_type * ret = NULL) { 87 | // Get bucket 88 | sig_t sig = m_hash_func(key); 89 | bucket_type * bucket = get_bucket_by_sig(sig); 90 | 91 | return bucket->remove(sig, key, ret); 92 | } 93 | 94 | // Update the value 95 | template 96 | bool update(const key_type & key, _Params & params, _Modifier &action) { 97 | sig_t sig = m_hash_func(key); 98 | bucket_type * bucket = get_bucket_by_sig(sig); 99 | 100 | return bucket->update(sig, key, params, action); 101 | } 102 | 103 | // Clear this hash table 104 | void clear(void) { 105 | if (m_bucket_array == NULL) 106 | return; 107 | 108 | for (uint32 i = 0; i < m_bucket_num; ++i) { 109 | m_bucket_array[i].clear(); 110 | } 111 | } 112 | 113 | uint32 capacity(void) const { 114 | if (m_bucket_array == NULL) 115 | return 0; 116 | 117 | uint32 capacity = 0; 118 | for (uint32 i = 0; i < m_bucket_num; ++i) { 119 | capacity += m_bucket_array[i].capacity(); 120 | } 121 | 122 | return capacity; 123 | } 124 | 125 | uint32 free_entries(void) const { 126 | if (m_bucket_array == NULL) 127 | return 0; 128 | 129 | uint32 free_entries = 0; 130 | for (uint32 i = 0; i < m_bucket_num; ++i) { 131 | free_entries += m_bucket_array[i].free_entries(); 132 | } 133 | 134 | return free_entries; 135 | } 136 | 137 | uint32 used_entries(void) const { 138 | if (m_bucket_array == NULL) 139 | return 0; 140 | 141 | uint32 count = 0; 142 | for (uint32 i = 0; i < m_bucket_num; ++i) { 143 | count += m_bucket_array[i].size(); 144 | } 145 | 146 | return count; 147 | } 148 | 149 | void str(ostream & os) const { 150 | os << "\nHash Table Information : " << std::endl; 151 | os << "** Total Entries : " << capacity() << std::endl; 152 | os << "** Free Entries : " << free_entries() << std::endl; 153 | os << "** Used Entries : " << used_entries() << std::endl; 154 | } 155 | 156 | private: 157 | bool initialize(void) { 158 | // Adjust bucket number if necessary 159 | if (!is_power_of_2(m_bucket_num)) 160 | m_bucket_num = convert_to_power_of_2(m_bucket_num); 161 | 162 | m_mask = m_bucket_num - 1; 163 | 164 | // Allocate memory for bucket 165 | char name[] = "bucket_array"; 166 | uint32 bucket_array_size_in_bytes = m_bucket_num * sizeof(bucket_type); 167 | m_bucket_array = static_cast(rte_zmalloc(name, bucket_array_size_in_bytes, 0)); 168 | if (m_bucket_array == NULL) { 169 | return false; 170 | } else { 171 | // Initialize Buckets 172 | for (uint32 i = 0; i < m_bucket_num; ++i) 173 | ::new (&m_bucket_array[i]) bucket_type; 174 | return true; 175 | } 176 | } 177 | 178 | void finalize(void) { 179 | if (m_bucket_array) { 180 | for (uint32 i = 0; i < m_bucket_num; ++i) { 181 | bucket_type * bucket = &(m_bucket_array[i]); 182 | // call the destructor of this bucket 183 | if (bucket) { 184 | bucket->~bucket_type(); 185 | } 186 | } 187 | rte_free(m_bucket_array); 188 | m_bucket_array = NULL; 189 | } 190 | } 191 | 192 | bucket_type * get_bucket_by_index(uint32 index) const { 193 | if (m_bucket_array == NULL) 194 | return NULL; 195 | 196 | if (index < m_bucket_num) 197 | return &m_bucket_array[index]; 198 | else 199 | return NULL; 200 | } 201 | 202 | bucket_type * get_bucket_by_sig(sig_t sig) const { 203 | return get_bucket_by_index(sig & m_mask); 204 | } 205 | 206 | 207 | private: 208 | hasher m_hash_func; 209 | uint32 m_mask; 210 | uint32 m_bucket_num; 211 | bucket_type *m_bucket_array; 212 | }; 213 | 214 | __SHM_STL_END 215 | 216 | #endif 217 | -------------------------------------------------------------------------------- /include/shm_node_pool.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This program is free software; you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation; either version 2 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program; if not, see . 15 | * 16 | * Copyright (C) Bruce.Li , 2014 17 | */ 18 | 19 | 20 | #ifndef __SHM_NODE_POOL_H_ 21 | #define __SHM_NODE_POOL_H_ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include "shm_hash_fun.h" 31 | #include "shm_common.h" 32 | 33 | __SHM_STL_BEGIN 34 | 35 | using std::ostream; 36 | 37 | /* typedef */ 38 | typedef u_int32_t sig_t; 39 | typedef u_int32_t uint32; 40 | typedef int32_t int32; 41 | 42 | template 43 | struct PrintNode { 44 | void operator() (const _Node & node, ostream & os) { 45 | os << "[" << node.index() << "] --> "; 46 | } 47 | }; 48 | 49 | template 50 | class Node { 51 | public: 52 | Node () : m_sig(0), m_next(NULL) {} 53 | ~Node () {} 54 | 55 | void fill(_Key k, _Value v, sig_t s) { 56 | m_key = k; 57 | m_value = v; 58 | m_sig = s; 59 | } 60 | 61 | void set_next(Node * next) {m_next = next;} 62 | void set_index(uint32 idx) {m_index = idx;} 63 | 64 | template 65 | void update(_Params& params, _Modifier &action) { 66 | action(m_value, params); 67 | } 68 | 69 | _Key key(void) const {return m_key;} 70 | _Value value(void) const {return m_value;} 71 | sig_t signature(void) const {return m_sig;} 72 | Node * next(void) const {return m_next;} 73 | uint32 index(void) const {return m_index;} 74 | 75 | void str(std::ostream &os) { 76 | os << "[ <" << m_key << ", " << m_value << ">, " << m_sig << " ] --> " << std::endl; 77 | } 78 | 79 | private: 80 | _Key m_key; 81 | _Value m_value; // The member of _Key and _Value should be volatile 82 | sig_t m_sig; // the sinature - hash value 83 | Node * volatile m_next; // the pointer of next node 84 | uint32 m_index; // the index of this node in node list, it should never be changed after initialization 85 | }; 86 | 87 | /* 88 | * @brief : FreeNodePool manages free nodes used by hashmap. A hashmap should always 89 | * get a free node from FreeNodePool and return it back when it decides to 90 | * erase a node from hashmap. 91 | * 92 | * FreeNodePool can resize itself if all free nodes are exhausted. It creates 93 | * a new free node list whose size is double of previous free node list. The 94 | * max resize count is 32 by default. It means you can create 32 free node 95 | * lists including the first one at most. 96 | * 97 | * All free nodes in free node lists are chained together and be accessed 98 | * from m_nodepool_head. 99 | * 100 | * This class provides following methods to programmers: 101 | * 1. GetNode - Get a free node from FreeNodePool 102 | * 2. PutNode - Put a node to FreeNodePool 103 | * 3. PutNodeList - Put a list of nodes to FreeNodePool 104 | * 105 | * Important: 106 | * 1. Programmers should not free any node outside of FreeNodePool 107 | * 108 | * Following is a chart to illustrate this class: 109 | * 110 | * m_freelist_array --> +-----------------------------------------------+ 111 | * | | | | | | | | | 112 | * +-----------------------------------------------+ 113 | * [the first list] | | [create the second free list if the first is exhausted] 114 | * V +-----> +-------------------------------+ 115 | * m_nodepool_head --> +-----+ | | | | | | | | | 116 | * | | +-------------------------------+ 117 | * +-----+ ^ 118 | * | | | 119 | * +-----+ | 120 | * | | | 121 | * +-----+ | 122 | * | | | [chain the new created free nodes to m_nodepool_head] 123 | * +-----+ | 124 | * |_______________| 125 | * 126 | * */ 127 | template 128 | class NodePool { 129 | public: 130 | typedef _Node node_type; 131 | static const uint32 MAX_RESIZE_COUNT = 5; 132 | static const uint32 DEFAULT_LIST_SIZE = 16; // The default size of the first free list 133 | 134 | NodePool(uint32 size = DEFAULT_LIST_SIZE) 135 | : m_init_size(size) 136 | , m_capacity(0) 137 | , m_free_entries(0) 138 | , m_freelist_num(0) 139 | , m_next_freelist_size(size) 140 | , m_nodepool_head(NULL) { 141 | for (uint32 i = 0; i < m_freelist_num; ++i) 142 | m_freelist_array[i] = NULL; 143 | 144 | resize(); 145 | } 146 | 147 | ~NodePool() { 148 | for (uint32 i = 0; i < m_freelist_num; ++i) { 149 | void * free_list = (void *)(m_freelist_array[i]); 150 | if (free_list != NULL) { 151 | rte_free(free_list); 152 | m_freelist_array[i] = NULL; 153 | } 154 | } 155 | 156 | m_capacity = 0; 157 | m_free_entries = 0; 158 | m_freelist_num = 0; 159 | m_next_freelist_size = m_init_size; 160 | m_nodepool_head = NULL; 161 | } 162 | 163 | // Get a free node 164 | node_type * get_node(void) { 165 | if (m_nodepool_head == NULL) 166 | resize(); 167 | 168 | if (m_nodepool_head == NULL) 169 | return NULL; 170 | 171 | // get the first free node 172 | node_type * head = m_nodepool_head; 173 | m_nodepool_head = head->next(); 174 | 175 | --m_free_entries; 176 | construct_node(head); 177 | 178 | return head; 179 | } 180 | 181 | // Return a node to free list 182 | void put_node(node_type * node) { 183 | if (node == NULL) 184 | return; 185 | 186 | // Put this node at the front of m_free_node_list 187 | node->set_next(m_nodepool_head); 188 | m_nodepool_head = node; 189 | 190 | ++m_free_entries; 191 | } 192 | 193 | // Return nodes in a bucket to free list 194 | void put_nodelist(node_type *start, node_type *end, uint32 size) { 195 | // If start or end is NULL, do nothing 196 | if (!start || !end) 197 | return; 198 | 199 | return_nodelist(start, end, size); 200 | } 201 | 202 | // Following three methods do not use lock 203 | uint32 capacity(void) const {return m_capacity;} 204 | uint32 free_entries(void) const {return m_free_entries;} 205 | 206 | void print(void) const { 207 | std::ostringstream os; 208 | print(os); 209 | std::cout << os.str().c_str() << std::endl; 210 | } 211 | 212 | void print(std::ostream & os) const { 213 | str(os); 214 | 215 | os << "\nFree Node Pool : " << std::endl; 216 | node_type * start = m_nodepool_head; 217 | PrintNode action; 218 | uint32 cnt = 0; 219 | while (start && cnt < m_free_entries) { 220 | action(*start, os); 221 | start = start->next(); 222 | ++cnt; 223 | } 224 | } 225 | 226 | private: 227 | // Create a new free node list and chain it to free node pool 228 | void resize(void) { 229 | // Have reached the maxinum size 230 | if (m_freelist_num >= MAX_RESIZE_COUNT) 231 | return; 232 | 233 | // Create a new free list 234 | uint32 node_cnt = m_next_freelist_size; 235 | uint32 list_size_in_byte = node_cnt * sizeof(node_type); 236 | std::ostringstream name; 237 | name << "NodePool_FreeList_" << m_freelist_num; 238 | node_type * new_list = static_cast(rte_zmalloc(name.str().c_str(), list_size_in_byte, 0)); 239 | if (new_list == NULL) 240 | return; 241 | 242 | // Now we have created the new free list successfully, add it to m_freelist_array 243 | // and free node pool 244 | initialize_freenode_list(new_list, node_cnt, m_capacity); 245 | m_freelist_array[m_freelist_num] = new_list; 246 | node_type * end_of_list = &new_list[node_cnt - 1]; 247 | return_nodelist(new_list, end_of_list, node_cnt); // PutNodeList will calculate m_free_entries 248 | 249 | // Calculate new capacity, free_list_num and next_free_list_size 250 | m_capacity += node_cnt; 251 | m_freelist_num++; 252 | m_next_freelist_size = node_cnt << 1; 253 | } 254 | 255 | void initialize_freenode_list(node_type *list, uint32 size, uint32 index_start) { 256 | uint32 i = 0; 257 | for ( ; i < size - 1; ++i) { 258 | // call the constructor of node_type 259 | node_type * node = &list[i]; 260 | construct_node(node); 261 | node->set_next(&list[i + 1]); 262 | node->set_index(index_start++); 263 | } 264 | 265 | // Set the index of last node 266 | list[i].set_index(index_start); 267 | } 268 | 269 | // This private function does not use lock 270 | void return_nodelist(node_type *start, node_type *end, uint32 size) { 271 | // If start or end is NULL, do nothing 272 | if (!start || !end) 273 | return; 274 | 275 | // Put the node list decribed by start and end at the front of m_nodepool_head 276 | end->set_next(m_nodepool_head); 277 | m_nodepool_head = start; 278 | m_free_entries += size; 279 | } 280 | 281 | void construct_node(node_type *node) {::new ((void *)node) node_type;} 282 | 283 | void str(std::ostream &os) const { 284 | os << "Node Pool Status : " << std::endl; 285 | os << "Capacity : " << m_capacity << std::endl; 286 | os << "Free entries : " << m_free_entries << std::endl; 287 | os << "Free list num : " << m_freelist_num << std::endl; 288 | } 289 | 290 | private: 291 | volatile uint32 m_init_size; 292 | volatile uint32 m_capacity; // the capacity of this free node pool 293 | volatile uint32 m_free_entries; // the count of available free nodes in this pool 294 | volatile uint32 m_freelist_num; // how many free lists we have now 295 | volatile uint32 m_next_freelist_size; // the size of next free list 296 | node_type * volatile m_nodepool_head; // the head of free node pool 297 | node_type * volatile m_freelist_array[MAX_RESIZE_COUNT]; // free lists 298 | }; 299 | 300 | __SHM_STL_END 301 | 302 | #endif 303 | -------------------------------------------------------------------------------- /include/shm_profiler.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHM_PROFILER_H_ 2 | #define __SHM_PROFILER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "shm_common.h" 13 | 14 | __SHM_STL_BEGIN 15 | 16 | class Profiler { 17 | public: 18 | static const uint32_t k_StatsSize = 20; 19 | static const uint32_t k_MaxCnt = 1 << 15; 20 | static const uint32_t k_MaxCycles = 1 << 30; 21 | static const uint32_t k_MaxNameSize = 128; 22 | 23 | class Stats { 24 | public: 25 | Stats(void) : cycles(0), cnt(0) {} 26 | uint64_t cycles; 27 | uint32_t cnt; 28 | }; 29 | 30 | Profiler(const char * name, uint32_t max_cnt = k_MaxCnt, uint32_t max_cycle = k_MaxCycles) 31 | : m_enabled(true) 32 | , m_ready_to_log(false) 33 | , m_max_cnt(max_cnt) 34 | , m_max_cycle(max_cycle) { 35 | copy_name(&m_filename[0], name); 36 | memset(&m_stats_name[0][0], 0, k_StatsSize * k_MaxNameSize); 37 | } 38 | ~Profiler() {} 39 | 40 | void set_stats_name(const uint32_t index, const char * name) {copy_name(&m_stats_name[index][0], name);} 41 | void disable(void) {m_enabled = false;} 42 | void enable(void) {m_enabled = true;} 43 | 44 | uint64_t start(void) { 45 | if (m_enabled && m_ready_to_log) { 46 | log_to_file(); 47 | clear(); 48 | } 49 | 50 | return read_tsc(); 51 | } 52 | 53 | uint64_t stop(uint32_t index, uint64_t start) { 54 | if (m_enabled) 55 | accumulate(index, read_tsc() - start); 56 | 57 | return read_tsc(); 58 | } 59 | 60 | void log_to_file(std::ostringstream &log) { 61 | std::ostringstream filename; 62 | filename << "/tmp/shm_profiler_" << m_filename << getpid() << ".txt"; 63 | std::ofstream ofs(filename.str().c_str(), std::ofstream::out); 64 | if (ofs.is_open()) { 65 | ofs << log.str().c_str() << std::endl; 66 | ofs.close(); 67 | } 68 | } 69 | 70 | private: 71 | uint64_t read_tsc(void) {return rte_rdtsc();} 72 | 73 | void copy_name(char * dst, const char * src) { 74 | if (src) { 75 | strncpy(dst, src, k_MaxNameSize - 1); 76 | dst[k_MaxNameSize - 1] = '\0'; 77 | } else { 78 | memset(dst, 0, k_MaxNameSize); 79 | } 80 | } 81 | 82 | void accumulate(uint32_t index, uint64_t delta) { 83 | if (index >= k_StatsSize) 84 | return; 85 | 86 | m_stats[index].cycles += delta; 87 | m_stats[index].cnt++; 88 | 89 | // If it exceeds the max count or cycles, we are ready to log 90 | if ((m_stats[index].cnt > m_max_cnt) || (m_stats[index].cycles > m_max_cycle)) 91 | m_ready_to_log = true; 92 | } 93 | 94 | void clear(void) { 95 | for (uint32_t i = 0; i < k_StatsSize; ++i) { 96 | m_stats[i].cycles = 0; 97 | m_stats[i].cnt = 0; 98 | } 99 | 100 | m_ready_to_log = false; 101 | } 102 | 103 | void log_to_file(void) { 104 | std::ostringstream filename; 105 | filename << "/tmp/shm_profiler_" << m_filename << getpid() << ".txt"; 106 | //filename << "/tmp/shm_profiler_" << getpid() << ".txt"; 107 | 108 | // Do not use std::ofstream::app here, it may cause a huge log file 109 | std::ofstream ofs(filename.str().c_str()); 110 | if (ofs.is_open()) { 111 | for (uint32_t i = 0; i < k_StatsSize; ++i) { 112 | if (m_stats[i].cnt > 0) { 113 | ofs << "Statistic " << i << " - " << &m_stats_name[i][0] 114 | << " *** cycles :" << (m_stats[i].cycles / m_stats[i].cnt) 115 | << ", cnt : " << m_stats[i].cnt << std::endl; 116 | } 117 | } 118 | ofs.close(); 119 | } 120 | } 121 | 122 | private: 123 | bool m_enabled; 124 | bool m_ready_to_log; 125 | char m_filename[k_MaxNameSize]; 126 | Stats m_stats[k_StatsSize]; 127 | char m_stats_name[k_StatsSize][k_MaxNameSize]; 128 | uint32_t m_max_cnt; 129 | uint32_t m_max_cycle; 130 | }; 131 | 132 | __SHM_STL_END 133 | 134 | #endif 135 | -------------------------------------------------------------------------------- /include/shm_stl_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHM_STL_CONFIG_H_ 2 | #define __SHM_STL_CONFIG_H_ 3 | 4 | #define __SHM_STL_BEGIN namespace shm_stl { 5 | #define __SHM_STL_END } 6 | 7 | #define __SHM_STL_TEMPLATE_NULL template <> 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/test.h: -------------------------------------------------------------------------------- 1 | #ifndef __TEST_H_ 2 | #define __TEST_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "shm_hash_map.h" 8 | 9 | #define OCCUPY_HASHMAP 10 | 11 | using shm_stl::hash_map; 12 | using namespace std; 13 | 14 | template 15 | struct Add { 16 | void operator() (volatile _T & old_v, _T &new_v) { 17 | old_v += new_v; 18 | } 19 | }; 20 | 21 | static int prompt_key(void) { 22 | int key; 23 | 24 | cout << " ... Please input the key [1 ~ 65536] : "; 25 | cin >> key; 26 | cout << " ... You just input " << key << endl; 27 | 28 | return key; 29 | } 30 | 31 | static int prompt_value(void) { 32 | int value; 33 | 34 | cout << " ... Please input the value[1 ~ 65536] : "; 35 | cin >> value; 36 | cout << " ... You just input " << value << endl; 37 | 38 | return value; 39 | } 40 | 41 | template 42 | void init(_HashMap &hashmap) { 43 | if (rte_eal_process_type() != RTE_PROC_PRIMARY) 44 | return; 45 | 46 | for (int i = 0; i < 1000; ++i) { 47 | if (!hashmap.insert(i, i * i)) 48 | cout << "Insert <" << i << ", " << i * i << "> fail!" << endl; 49 | } 50 | 51 | hashmap.print(); 52 | } 53 | 54 | template 55 | //void test(const char *name) { 56 | void test() { 57 | char name[] = "test"; 58 | hash_map<_Key, _Value> hashmap(name, 8, 8); 59 | hashmap.create_or_attach(); 60 | //init(hashmap); 61 | const rte_memzone * zone; 62 | volatile bool * flag = NULL; 63 | char zone_name[] = "share_flag"; 64 | 65 | if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 66 | zone = rte_memzone_reserve(zone_name, sizeof(bool), 0, 0); 67 | flag = (bool*)zone->addr; 68 | *flag = false; 69 | } else { 70 | zone = rte_memzone_lookup(zone_name); 71 | flag = (bool*)zone->addr; 72 | } 73 | 74 | cout << "Please input your choice : a[dd], d[elete], f[ind], m[odify], s[how], q[uit]" << endl; 75 | 76 | while (1) { 77 | int input = getchar(); 78 | int quit = false; 79 | int key = 0; 80 | int value = 0; 81 | int count = 20000; 82 | 83 | switch (input) { 84 | case 'a': 85 | key = prompt_key(); 86 | value = prompt_value(); 87 | hashmap.insert(key, value); 88 | break; 89 | case 'd': 90 | key = prompt_key(); 91 | hashmap.erase(key); 92 | break; 93 | case 'f': 94 | key = prompt_key(); 95 | if (hashmap.find(key, &value)) { 96 | cout << "Key : " << key << " Value : " << value << endl; 97 | } 98 | break; 99 | case 'm': 100 | key = prompt_key(); 101 | value = prompt_value(); 102 | shm_stl::Assignment<_Value> assign; 103 | hashmap.update(key, value, assign); 104 | break; 105 | case 's': 106 | hashmap.print(); 107 | break; 108 | case 'q': 109 | quit = true; 110 | break; 111 | 112 | case 't': 113 | // test lock on multi processes 114 | key = prompt_key(); 115 | value = prompt_value(); 116 | Add<_Value> add; 117 | if (rte_eal_process_type() == RTE_PROC_PRIMARY) { 118 | cout << "primary process! " << endl; 119 | if (*flag) 120 | cout << "flag is true! " << endl; 121 | else 122 | cout << "flag is false! " << endl; 123 | *flag = true; 124 | while (count > 0) { 125 | hashmap.update(key, value, add); 126 | count--; 127 | } 128 | } else { 129 | cout << "primary process! " << endl; 130 | if (*flag) 131 | cout << "flag is true! " << endl; 132 | else 133 | cout << "flag is false! " << endl; 134 | while (*flag == false) {} 135 | while (count > 0) { 136 | hashmap.update(key, value, add); 137 | count--; 138 | } 139 | } 140 | break; 141 | 142 | default: 143 | continue; 144 | } 145 | 146 | cout << "Please input your choice : a[dd], d[elete], f[ind], m[odify], s[how], q[uit]" << endl; 147 | 148 | if (quit) 149 | break; 150 | } 151 | 152 | return; 153 | } 154 | 155 | #endif 156 | -------------------------------------------------------------------------------- /include/test/Makefile: -------------------------------------------------------------------------------- 1 | CC = g++ 2 | FLAGS = -DDEBUG 3 | TARGETDIR = build 4 | INCLUDE = -I../ 5 | 6 | vpath %.h ../ 7 | 8 | test : main.o 9 | $(CC) -o test main.o 10 | 11 | main.o : main.cpp 12 | $(CC) $(FLAGS) $(INCLUDE) -c main.cpp 13 | 14 | clean : 15 | rm -f *.o test 16 | -------------------------------------------------------------------------------- /include/test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | 4 | using namespace std; 5 | 6 | int main(void) { 7 | unsigned int a = 1 << 10; 8 | unsigned int b = (1 << 30) - 1; 9 | 10 | if (is_power_of_2(a)) 11 | cout << a << " is power of 2" << endl; 12 | else { 13 | cout << a << " is not power of 2" << endl; 14 | int c = convert_to_power_of_2(a); 15 | cout << "Convert " << a << " to power of 2 : " << c << endl; 16 | } 17 | 18 | if (is_power_of_2(b)) 19 | cout << b << " is power of 2" << endl; 20 | else { 21 | cout << b << " is not power of 2" << endl; 22 | int c = convert_to_power_of_2(b); 23 | cout << "Convert " << b << " to power of 2 : " << c << endl; 24 | } 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /include/test/main.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiangwlee/more-effective-dpdk-share-hashmap/c68896e357780783bbf8ca104165de92424e2d42/include/test/main.o -------------------------------------------------------------------------------- /include/test/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jiangwlee/more-effective-dpdk-share-hashmap/c68896e357780783bbf8ca104165de92424e2d42/include/test/test -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "include/test.h" 18 | 19 | using namespace std; 20 | 21 | int main(int argc, char **argv) { 22 | int ret; 23 | 24 | ret = rte_eal_init(argc, argv); 25 | if (ret < 0) 26 | rte_panic("Cannot init EAL\n"); 27 | 28 | char name[] = "test"; 29 | shm_stl::hash_map hs(name); 30 | hs.create_or_attach(); 31 | hs.insert(1, 10); 32 | 33 | int value = 0; 34 | if (hs.find(1, &value)) 35 | cout << "Key : 1 --> Value : " << value << endl; 36 | 37 | int new_value = 11; 38 | Add add; 39 | hs.update(1, new_value, add); 40 | 41 | if (hs.find(1, &value)) 42 | cout << "Key : 1 --> Value : " << value << endl; 43 | 44 | if (hs.erase(1, &value)) 45 | cout << "Erase Key : 1 --> Value " << value << " from hash_map!" << endl; 46 | else 47 | cout << "Erase Key : 1 fail!" << endl; 48 | 49 | 50 | if (!hs.find(1, &value)) 51 | cout << "Can't find Key 1!" << endl; 52 | else 53 | cout << "Key : 1 --> Value : " << value << endl; 54 | 55 | //test(); 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /mk/internal/rte.compile-pre.mk: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | # 33 | # Common to rte.lib.mk, rte.app.mk, rte.obj.mk 34 | # 35 | CXX-suffix = cpp 36 | 37 | SRCS-all := $(SRCS-y) $(SRCS-n) $(SRCS-) 38 | 39 | # convert source to obj file 40 | src2obj = $(strip $(patsubst %.c,%.o,\ 41 | $(patsubst %.$(CXX-suffix),%.o,\ 42 | $(patsubst %.S,%_s.o,$(1))))) 43 | 44 | # add a dot in front of the file name 45 | dotfile = $(strip $(foreach f,$(1),\ 46 | $(join $(dir $f),.$(notdir $f)))) 47 | 48 | # convert source/obj files into dot-dep filename (does not 49 | # include .S files) 50 | src2dep = $(strip $(call dotfile,$(patsubst %.c,%.o.d, \ 51 | $(patsubst %.$(CXX-suffix),%.o.d, \ 52 | $(patsubst %.S,,$(1)))))) 53 | obj2dep = $(strip $(call dotfile,$(patsubst %.o,%.o.d,$(1)))) 54 | 55 | # convert source/obj files into dot-cmd filename 56 | src2cmd = $(strip $(call dotfile,$(patsubst %.c,%.o.cmd, \ 57 | $(patsubst %.$(CXX-suffix),%.o.cmd, \ 58 | $(patsubst %.S,%_s.o.cmd,$(1)))))) 59 | obj2cmd = $(strip $(call dotfile,$(patsubst %.o,%.o.cmd,$(1)))) 60 | 61 | OBJS-y := $(call src2obj,$(SRCS-y)) 62 | OBJS-n := $(call src2obj,$(SRCS-n)) 63 | OBJS- := $(call src2obj,$(SRCS-)) 64 | OBJS-all := $(filter-out $(SRCS-all),$(OBJS-y) $(OBJS-n) $(OBJS-)) 65 | 66 | DEPS-y := $(call src2dep,$(SRCS-y)) 67 | DEPS-n := $(call src2dep,$(SRCS-n)) 68 | DEPS- := $(call src2dep,$(SRCS-)) 69 | DEPS-all := $(DEPS-y) $(DEPS-n) $(DEPS-) 70 | DEPSTMP-all := $(DEPS-all:%.d=%.d.tmp) 71 | 72 | CMDS-y := $(call src2cmd,$(SRCS-y)) 73 | CMDS-n := $(call src2cmd,$(SRCS-n)) 74 | CMDS- := $(call src2cmd,$(SRCS-)) 75 | CMDS-all := $(CMDS-y) $(CMDS-n) $(CMDS-) 76 | 77 | -include $(DEPS-y) $(CMDS-y) 78 | 79 | # command to compile a .c file to generate an object 80 | ifeq ($(USE_HOST),1) 81 | C_TO_O = $(HOSTCC) -Wp,-MD,$(call obj2dep,$(@)).tmp $(HOST_CFLAGS) \ 82 | $(CFLAGS_$(@)) $(HOST_EXTRA_CFLAGS) -o $@ -c $< 83 | C_TO_O_STR = $(subst ','\'',$(C_TO_O)) #'# fix syntax highlight 84 | C_TO_O_DISP = $(if $(V),"$(C_TO_O_STR)"," HOSTCC $(@)") 85 | else 86 | C_TO_O = $(CC) -Wp,-MD,$(call obj2dep,$(@)).tmp $(CFLAGS) \ 87 | $(CFLAGS_$(@)) $(EXTRA_CFLAGS) -o $@ -c $< 88 | C_TO_O_STR = $(subst ','\'',$(C_TO_O)) #'# fix syntax highlight 89 | C_TO_O_DISP = $(if $(V),"$(C_TO_O_STR)"," CC $(@)") 90 | endif 91 | C_TO_O_CMD = 'cmd_$@ = $(C_TO_O_STR)' 92 | C_TO_O_DO = @set -e; \ 93 | echo $(C_TO_O_DISP); \ 94 | $(C_TO_O) && \ 95 | echo $(C_TO_O_CMD) > $(call obj2cmd,$(@)) && \ 96 | sed 's,'$@':,dep_'$@' =,' $(call obj2dep,$(@)).tmp > $(call obj2dep,$(@)) && \ 97 | rm -f $(call obj2dep,$(@)).tmp 98 | 99 | # return an empty string if string are equal 100 | compare = $(strip $(subst $(1),,$(2)) $(subst $(2),,$(1))) 101 | 102 | # return a non-empty string if the dst file does not exist 103 | file_missing = $(call compare,$(wildcard $@),$@) 104 | 105 | # return a non-empty string if cmdline changed 106 | cmdline_changed = $(call compare,$(strip $(cmd_$@)),$(strip $(1))) 107 | 108 | # return a non-empty string if a dependency file does not exist 109 | depfile_missing = $(call compare,$(wildcard $(dep_$@)),$(dep_$@)) 110 | 111 | # return an empty string if no prereq is newer than target 112 | # - $^ -> names of all the prerequisites 113 | # - $(wildcard $^) -> every existing prereq 114 | # - $(filter-out $(wildcard $^),$^) -> every prereq that don't 115 | # exist (filter-out removes existing ones from the list) 116 | # - $? -> names of all the prerequisites newer than target 117 | depfile_newer = $(strip $(filter-out FORCE,$? \ 118 | $(filter-out $(wildcard $^),$^))) 119 | 120 | # return 1 if parameter is a non-empty string, else 0 121 | boolean = $(if $1,1,0) 122 | 123 | # 124 | # Compile .c file if needed 125 | # Note: dep_$$@ is from the .d file and DEP_$$@ can be specified by 126 | # user (by default it is empty) 127 | # 128 | .SECONDEXPANSION: 129 | %.o: %.c $$(wildcard $$(dep_$$@)) $$(DEP_$$(@)) FORCE 130 | @[ -d $(dir $@) ] || mkdir -p $(dir $@) 131 | $(if $(D),\ 132 | @echo -n "$< -> $@ " ; \ 133 | echo -n "file_missing=$(call boolean,$(file_missing)) " ; \ 134 | echo -n "cmdline_changed=$(call boolean,$(call cmdline_changed,$(C_TO_O))) " ; \ 135 | echo -n "depfile_missing=$(call boolean,$(depfile_missing)) " ; \ 136 | echo "depfile_newer=$(call boolean,$(depfile_newer))") 137 | $(if $(or \ 138 | $(file_missing),\ 139 | $(call cmdline_changed,$(C_TO_O)),\ 140 | $(depfile_missing),\ 141 | $(depfile_newer)),\ 142 | $(C_TO_O_DO)) 143 | 144 | %.o: %.$(CXX-suffix) $$(wildcard $$(dep_$$@)) $$(DEP_$$(@)) FORCE 145 | @[ -d $(dir $@) ] || mkdir -p $(dir $@) 146 | $(if $(D),\ 147 | @echo -n "$< -> $@ " ; \ 148 | echo -n "file_missing=$(call boolean,$(file_missing)) " ; \ 149 | echo -n "cmdline_changed=$(call boolean,$(call cmdline_changed,$(C_TO_O))) " ; \ 150 | echo -n "depfile_missing=$(call boolean,$(depfile_missing)) " ; \ 151 | echo "depfile_newer=$(call boolean,$(depfile_newer))") 152 | $(if $(or \ 153 | $(file_missing),\ 154 | $(call cmdline_changed,$(C_TO_O)),\ 155 | $(depfile_missing),\ 156 | $(depfile_newer)),\ 157 | $(C_TO_O_DO)) 158 | 159 | # command to assemble a .S file to generate an object 160 | ifeq ($(USE_HOST),1) 161 | S_TO_O = $(CPP) $(HOST_CPPFLAGS) $($(@)_CPPFLAGS) $(HOST_EXTRA_CPPFLAGS) $< $(@).tmp && \ 162 | $(HOSTAS) $(HOST_ASFLAGS) $($(@)_ASFLAGS) $(HOST_EXTRA_ASFLAGS) -o $@ $(@).tmp 163 | S_TO_O_STR = $(subst ','\'',$(S_TO_O)) #'# fix syntax highlight 164 | S_TO_O_DISP = $(if $(V),"$(S_TO_O_STR)"," HOSTAS $(@)") 165 | else 166 | S_TO_O = $(CPP) $(CPPFLAGS) $($(@)_CPPFLAGS) $(EXTRA_CPPFLAGS) $< -o $(@).tmp && \ 167 | $(AS) $(ASFLAGS) $($(@)_ASFLAGS) $(EXTRA_ASFLAGS) -o $@ $(@).tmp 168 | S_TO_O_STR = $(subst ','\'',$(S_TO_O)) #'# fix syntax highlight 169 | S_TO_O_DISP = $(if $(V),"$(S_TO_O_STR)"," AS $(@)") 170 | endif 171 | 172 | S_TO_O_CMD = "cmd_$@ = $(S_TO_O_STR)" 173 | S_TO_O_DO = @set -e; \ 174 | echo $(S_TO_O_DISP); \ 175 | $(S_TO_O) && \ 176 | echo $(S_TO_O_CMD) > $(call obj2cmd,$(@)) 177 | 178 | # 179 | # Compile .S file if needed 180 | # Note: DEP_$$@ can be specified by user (by default it is empty) 181 | # 182 | %_s.o: %.S $$(DEP_$$@) FORCE 183 | @[ ! -d $(dir $@) ] || mkdir -p $(dir $@) 184 | $(if $(D),\ 185 | @echo -n "$< -> $@ " ; \ 186 | echo -n "file_missing=$(call boolean,$(file_missing)) " ; \ 187 | echo -n "cmdline_changed=$(call boolean,$(call cmdline_changed,$(S_TO_O_STR))) " ; \ 188 | echo -n "depfile_missing=$(call boolean,$(depfile_missing)) " ; \ 189 | echo "depfile_newer=$(call boolean,$(depfile_newer)) ") 190 | $(if $(or \ 191 | $(file_missing),\ 192 | $(call cmdline_changed,$(S_TO_O_STR)),\ 193 | $(depfile_missing),\ 194 | $(depfile_newer)),\ 195 | $(S_TO_O_DO)) 196 | -------------------------------------------------------------------------------- /mk/toolchain/gcc/rte.vars.mk: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | # 33 | # toolchain: 34 | # 35 | # - define CC, LD, AR, AS, ... (overriden by cmdline value) 36 | # - define TOOLCHAIN_CFLAGS variable (overriden by cmdline value) 37 | # - define TOOLCHAIN_LDFLAGS variable (overriden by cmdline value) 38 | # - define TOOLCHAIN_ASFLAGS variable (overriden by cmdline value) 39 | # 40 | # examples for RTE_TOOLCHAIN: gcc, icc 41 | # 42 | 43 | CC = $(CROSS)gcc 44 | CPP = $(CROSS)cpp 45 | # for now, we don't use as but nasm. 46 | # AS = $(CROSS)as 47 | AS = nasm 48 | AR = $(CROSS)ar 49 | LD = $(CROSS)ld 50 | OBJCOPY = $(CROSS)objcopy 51 | OBJDUMP = $(CROSS)objdump 52 | STRIP = $(CROSS)strip 53 | READELF = $(CROSS)readelf 54 | GCOV = $(CROSS)gcov 55 | 56 | HOSTCC = gcc 57 | HOSTAS = as 58 | 59 | TOOLCHAIN_ASFLAGS = 60 | TOOLCHAIN_CFLAGS = 61 | TOOLCHAIN_LDFLAGS = 62 | 63 | ifeq ($(CONFIG_RTE_LIBRTE_GCOV),y) 64 | TOOLCHAIN_CFLAGS += --coverage 65 | TOOLCHAIN_LDFLAGS += --coverage 66 | ifeq (,$(findstring -O0,$(EXTRA_CFLAGS))) 67 | $(warning "EXTRA_CFLAGS doesn't contains -O0, coverage will be inaccurate with optimizations enabled") 68 | endif 69 | endif 70 | 71 | ifeq ($(CC), $(CROSS)g++) 72 | TOOLCHAIN_CFLAGS += -D__STDC_LIMIT_MACROS 73 | WERROR_FLAGS := -W -Wall -Werror 74 | WERROR_FLAGS += -Wmissing-declarations -Wpointer-arith 75 | WERROR_FLAGS += -Wcast-align -Wcast-qual 76 | else 77 | WERROR_FLAGS := -W -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes 78 | WERROR_FLAGS += -Wmissing-declarations -Wold-style-definition -Wpointer-arith 79 | WERROR_FLAGS += -Wcast-align -Wnested-externs -Wcast-qual 80 | endif 81 | WERROR_FLAGS += -Wformat-nonliteral -Wformat-security 82 | 83 | ifeq ($(CONFIG_RTE_EXEC_ENV),"linuxapp") 84 | # These trigger warnings in newlib, so can't be used for baremetal 85 | WERROR_FLAGS += -Wundef -Wwrite-strings 86 | endif 87 | 88 | # process cpu flags 89 | include $(RTE_SDK)/mk/toolchain/$(RTE_TOOLCHAIN)/rte.toolchain-compat.mk 90 | 91 | export CC AS AR LD OBJCOPY OBJDUMP STRIP READELF 92 | export TOOLCHAIN_CFLAGS TOOLCHAIN_LDFLAGS TOOLCHAIN_ASFLAGS 93 | --------------------------------------------------------------------------------