mirror of https://github.com/grpc/grpc.git
commit
93aedbfc6a
41 changed files with 1998 additions and 549 deletions
@ -0,0 +1,302 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/ext/census/intrusive_hash_map.h" |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
extern bool hm_index_compare(const hm_index *A, const hm_index *B); |
||||||
|
|
||||||
|
/* Simple hashing function that takes lower 32 bits. */ |
||||||
|
static inline uint32_t chunked_vector_hasher(uint64_t key) { |
||||||
|
return (uint32_t)key; |
||||||
|
} |
||||||
|
|
||||||
|
/* Vector chunks are 1MiB divided by pointer size. */ |
||||||
|
static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); |
||||||
|
|
||||||
|
/* Helper functions which return buckets from the chunked vector. */ |
||||||
|
static inline void **get_mutable_bucket(const chunked_vector *buckets, |
||||||
|
uint32_t index) { |
||||||
|
if (index < VECTOR_CHUNK_SIZE) { |
||||||
|
return &buckets->first_[index]; |
||||||
|
} |
||||||
|
size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; |
||||||
|
return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; |
||||||
|
} |
||||||
|
|
||||||
|
static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { |
||||||
|
if (index < VECTOR_CHUNK_SIZE) { |
||||||
|
return buckets->first_[index]; |
||||||
|
} |
||||||
|
size_t rest_index = (index - VECTOR_CHUNK_SIZE) / VECTOR_CHUNK_SIZE; |
||||||
|
return buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; |
||||||
|
} |
||||||
|
|
||||||
|
/* Helper function. */ |
||||||
|
static inline size_t RestSize(const chunked_vector *vec) { |
||||||
|
return (vec->size_ <= VECTOR_CHUNK_SIZE) |
||||||
|
? 0 |
||||||
|
: (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Initialize chunked vector to size of 0. */ |
||||||
|
static void chunked_vector_init(chunked_vector *vec) { |
||||||
|
vec->size_ = 0; |
||||||
|
vec->first_ = NULL; |
||||||
|
vec->rest_ = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* Clear chunked vector and free all memory that has been allocated then
|
||||||
|
initialize chunked vector. */ |
||||||
|
static void chunked_vector_clear(chunked_vector *vec) { |
||||||
|
if (vec->first_ != NULL) { |
||||||
|
gpr_free(vec->first_); |
||||||
|
} |
||||||
|
if (vec->rest_ != NULL) { |
||||||
|
size_t rest_size = RestSize(vec); |
||||||
|
for (size_t i = 0; i < rest_size; ++i) { |
||||||
|
if (vec->rest_[i] != NULL) { |
||||||
|
gpr_free(vec->rest_[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
gpr_free(vec->rest_); |
||||||
|
} |
||||||
|
chunked_vector_init(vec); |
||||||
|
} |
||||||
|
|
||||||
|
/* Clear chunked vector and then resize it to n entries. Allow the first 1MB to
|
||||||
|
be read w/o an extra cache miss. The rest of the elements are stored in an |
||||||
|
array of arrays to avoid large mallocs. */ |
||||||
|
static void chunked_vector_reset(chunked_vector *vec, size_t n) { |
||||||
|
chunked_vector_clear(vec); |
||||||
|
vec->size_ = n; |
||||||
|
if (n <= VECTOR_CHUNK_SIZE) { |
||||||
|
vec->first_ = (void **)gpr_malloc(sizeof(void *) * n); |
||||||
|
memset(vec->first_, 0, sizeof(void *) * n); |
||||||
|
} else { |
||||||
|
vec->first_ = (void **)gpr_malloc(sizeof(void *) * VECTOR_CHUNK_SIZE); |
||||||
|
memset(vec->first_, 0, sizeof(void *) * VECTOR_CHUNK_SIZE); |
||||||
|
size_t rest_size = RestSize(vec); |
||||||
|
vec->rest_ = (void ***)gpr_malloc(sizeof(void **) * rest_size); |
||||||
|
memset(vec->rest_, 0, sizeof(void **) * rest_size); |
||||||
|
int i = 0; |
||||||
|
n -= VECTOR_CHUNK_SIZE; |
||||||
|
while (n > 0) { |
||||||
|
size_t this_size = GPR_MIN(n, VECTOR_CHUNK_SIZE); |
||||||
|
vec->rest_[i] = (void **)gpr_malloc(sizeof(void *) * this_size); |
||||||
|
memset(vec->rest_[i], 0, sizeof(void *) * this_size); |
||||||
|
n -= this_size; |
||||||
|
++i; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_init(intrusive_hash_map *hash_map, |
||||||
|
uint32_t initial_log2_table_size) { |
||||||
|
hash_map->log2_num_buckets = initial_log2_table_size; |
||||||
|
hash_map->num_items = 0; |
||||||
|
uint32_t num_buckets = (uint32_t)1 << hash_map->log2_num_buckets; |
||||||
|
hash_map->extend_threshold = num_buckets >> 1; |
||||||
|
chunked_vector_init(&hash_map->buckets); |
||||||
|
chunked_vector_reset(&hash_map->buckets, num_buckets); |
||||||
|
hash_map->hash_mask = num_buckets - 1; |
||||||
|
} |
||||||
|
|
||||||
|
bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map) { |
||||||
|
return hash_map->num_items == 0; |
||||||
|
} |
||||||
|
|
||||||
|
size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map) { |
||||||
|
return hash_map->num_items; |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx) { |
||||||
|
idx->bucket_index = (uint32_t)hash_map->buckets.size_; |
||||||
|
GPR_ASSERT(idx->bucket_index <= UINT32_MAX); |
||||||
|
idx->item = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_next(const intrusive_hash_map *hash_map, |
||||||
|
hm_index *idx) { |
||||||
|
idx->item = idx->item->hash_link; |
||||||
|
while (idx->item == NULL) { |
||||||
|
idx->bucket_index++; |
||||||
|
if (idx->bucket_index >= hash_map->buckets.size_) { |
||||||
|
/* Reached end of table. */ |
||||||
|
idx->item = NULL; |
||||||
|
return; |
||||||
|
} |
||||||
|
idx->item = (hm_item *)get_bucket(&hash_map->buckets, idx->bucket_index); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, |
||||||
|
hm_index *idx) { |
||||||
|
for (uint32_t i = 0; i < hash_map->buckets.size_; ++i) { |
||||||
|
if (get_bucket(&hash_map->buckets, i) != NULL) { |
||||||
|
idx->bucket_index = i; |
||||||
|
idx->item = (hm_item *)get_bucket(&hash_map->buckets, i); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
intrusive_hash_map_end(hash_map, idx); |
||||||
|
} |
||||||
|
|
||||||
|
hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, |
||||||
|
uint64_t key) { |
||||||
|
uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; |
||||||
|
|
||||||
|
hm_item *p = (hm_item *)get_bucket(&hash_map->buckets, index); |
||||||
|
while (p != NULL) { |
||||||
|
if (key == p->key) { |
||||||
|
return p; |
||||||
|
} |
||||||
|
p = p->hash_link; |
||||||
|
} |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { |
||||||
|
uint32_t index = chunked_vector_hasher(key) & hash_map->hash_mask; |
||||||
|
|
||||||
|
hm_item **slot = (hm_item **)get_mutable_bucket(&hash_map->buckets, index); |
||||||
|
hm_item *p = *slot; |
||||||
|
if (p == NULL) { |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
if (key == p->key) { |
||||||
|
*slot = p->hash_link; |
||||||
|
p->hash_link = NULL; |
||||||
|
hash_map->num_items--; |
||||||
|
return p; |
||||||
|
} |
||||||
|
|
||||||
|
hm_item *prev = p; |
||||||
|
p = p->hash_link; |
||||||
|
|
||||||
|
while (p) { |
||||||
|
if (key == p->key) { |
||||||
|
prev->hash_link = p->hash_link; |
||||||
|
p->hash_link = NULL; |
||||||
|
hash_map->num_items--; |
||||||
|
return p; |
||||||
|
} |
||||||
|
prev = p; |
||||||
|
p = p->hash_link; |
||||||
|
} |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
/* Insert an hm_item* into the underlying chunked vector. hash_mask is
|
||||||
|
* array_size-1. Returns true if it is a new hm_item and false if the hm_item |
||||||
|
* already existed. |
||||||
|
*/ |
||||||
|
static inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, |
||||||
|
uint32_t hash_mask, |
||||||
|
hm_item *item) { |
||||||
|
const uint64_t key = item->key; |
||||||
|
uint32_t index = chunked_vector_hasher(key) & hash_mask; |
||||||
|
hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index); |
||||||
|
hm_item *p = *slot; |
||||||
|
item->hash_link = p; |
||||||
|
|
||||||
|
/* Check to see if key already exists. */ |
||||||
|
while (p) { |
||||||
|
if (p->key == key) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
p = p->hash_link; |
||||||
|
} |
||||||
|
|
||||||
|
/* Otherwise add new entry. */ |
||||||
|
*slot = item; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/* Extend the allocated number of elements in the hash map by a factor of 2. */ |
||||||
|
void intrusive_hash_map_extend(intrusive_hash_map *hash_map) { |
||||||
|
uint32_t new_log2_num_buckets = 1 + hash_map->log2_num_buckets; |
||||||
|
uint32_t new_num_buckets = (uint32_t)1 << new_log2_num_buckets; |
||||||
|
GPR_ASSERT(new_num_buckets <= UINT32_MAX && new_num_buckets > 0); |
||||||
|
chunked_vector new_buckets; |
||||||
|
chunked_vector_init(&new_buckets); |
||||||
|
chunked_vector_reset(&new_buckets, new_num_buckets); |
||||||
|
uint32_t new_hash_mask = new_num_buckets - 1; |
||||||
|
|
||||||
|
hm_index cur_idx; |
||||||
|
hm_index end_idx; |
||||||
|
intrusive_hash_map_end(hash_map, &end_idx); |
||||||
|
intrusive_hash_map_begin(hash_map, &cur_idx); |
||||||
|
while (!hm_index_compare(&cur_idx, &end_idx)) { |
||||||
|
hm_item *new_item = cur_idx.item; |
||||||
|
intrusive_hash_map_next(hash_map, &cur_idx); |
||||||
|
intrusive_hash_map_internal_insert(&new_buckets, new_hash_mask, new_item); |
||||||
|
} |
||||||
|
|
||||||
|
/* Set values for new chunked_vector. extend_threshold is set to half of
|
||||||
|
* new_num_buckets. */ |
||||||
|
hash_map->log2_num_buckets = new_log2_num_buckets; |
||||||
|
chunked_vector_clear(&hash_map->buckets); |
||||||
|
hash_map->buckets = new_buckets; |
||||||
|
hash_map->hash_mask = new_hash_mask; |
||||||
|
hash_map->extend_threshold = new_num_buckets >> 1; |
||||||
|
} |
||||||
|
|
||||||
|
/* Insert a hm_item. The hm_item must remain live until it is removed from the
|
||||||
|
table. This object does not take the ownership of hm_item. The caller must |
||||||
|
remove this hm_item from the table and delete it before this table is |
||||||
|
deleted. If hm_item exists already num_items is not changed. */ |
||||||
|
bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item) { |
||||||
|
if (hash_map->num_items >= hash_map->extend_threshold) { |
||||||
|
intrusive_hash_map_extend(hash_map); |
||||||
|
} |
||||||
|
if (intrusive_hash_map_internal_insert(&hash_map->buckets, |
||||||
|
hash_map->hash_mask, item)) { |
||||||
|
hash_map->num_items++; |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_clear(intrusive_hash_map *hash_map, |
||||||
|
void (*free_object)(void *)) { |
||||||
|
hm_index cur; |
||||||
|
hm_index end; |
||||||
|
intrusive_hash_map_end(hash_map, &end); |
||||||
|
intrusive_hash_map_begin(hash_map, &cur); |
||||||
|
|
||||||
|
while (!hm_index_compare(&cur, &end)) { |
||||||
|
hm_index next = cur; |
||||||
|
intrusive_hash_map_next(hash_map, &next); |
||||||
|
if (cur.item != NULL) { |
||||||
|
hm_item *item = intrusive_hash_map_erase(hash_map, cur.item->key); |
||||||
|
(*free_object)((void *)item); |
||||||
|
gpr_free(item); |
||||||
|
} |
||||||
|
cur = next; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void intrusive_hash_map_free(intrusive_hash_map *hash_map, |
||||||
|
void (*free_object)(void *)) { |
||||||
|
intrusive_hash_map_clear(hash_map, (*free_object)); |
||||||
|
hash_map->num_items = 0; |
||||||
|
hash_map->extend_threshold = 0; |
||||||
|
hash_map->log2_num_buckets = 0; |
||||||
|
hash_map->hash_mask = 0; |
||||||
|
chunked_vector_clear(&hash_map->buckets); |
||||||
|
} |
@ -0,0 +1,150 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H |
||||||
|
#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H |
||||||
|
|
||||||
|
#include "src/core/ext/census/intrusive_hash_map_internal.h" |
||||||
|
|
||||||
|
/* intrusive_hash_map is a fast chained hash table. This hash map is faster than
|
||||||
|
* a dense hash map when the application calls insert and erase more often than |
||||||
|
* find. When the workload is dominated by find() a dense hash map may be |
||||||
|
* faster. |
||||||
|
* |
||||||
|
* intrusive_hash_map uses an intrusive header placed within a user defined |
||||||
|
* struct. The header field IHM_key MUST be set to a valid value before |
||||||
|
* insertion into the hash map or undefined behavior may occur. The header field |
||||||
|
* IHM_hash_link MUST to be set to NULL initially. |
||||||
|
* |
||||||
|
* EXAMPLE USAGE: |
||||||
|
* |
||||||
|
* typedef struct string_item { |
||||||
|
* INTRUSIVE_HASH_MAP_HEADER; |
||||||
|
* // User data.
|
||||||
|
* char *str_buf; |
||||||
|
* uint16_t len; |
||||||
|
* } string_item; |
||||||
|
* |
||||||
|
* static string_item *make_string_item(uint64_t key, const char *buf, |
||||||
|
* uint16_t len) { |
||||||
|
* string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); |
||||||
|
* item->IHM_key = key; |
||||||
|
* item->IHM_hash_link = NULL; |
||||||
|
* item->len = len; |
||||||
|
* item->str_buf = (char *)malloc(len); |
||||||
|
* memcpy(item->str_buf, buf, len); |
||||||
|
* return item; |
||||||
|
* } |
||||||
|
* |
||||||
|
* intrusive_hash_map hash_map; |
||||||
|
* intrusive_hash_map_init(&hash_map, 4); |
||||||
|
* string_item *new_item1 = make_string_item(10, "test1", 5); |
||||||
|
* bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); |
||||||
|
* |
||||||
|
* string_item *item1 = |
||||||
|
* (string_item *)intrusive_hash_map_find(&hash_map, 10); |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Hash map item. Stores key and a pointer to the actual object. A user defined
|
||||||
|
* version of this can be passed in provided the first 2 entries (key and |
||||||
|
* hash_link) are the same. These entries must be first in the user defined |
||||||
|
* struct. Pointer to struct will need to be cast as (hm_item *) when passed to |
||||||
|
* hash map. This allows it to be intrusive. */ |
||||||
|
typedef struct hm_item { |
||||||
|
uint64_t key; |
||||||
|
struct hm_item *hash_link; |
||||||
|
/* Optional user defined data after this. */ |
||||||
|
} hm_item; |
||||||
|
|
||||||
|
/* Macro provided for ease of use. This must be first in the user defined
|
||||||
|
* struct (i.e. uint64_t key and hm_item * must be the first two elements in |
||||||
|
* that order). */ |
||||||
|
#define INTRUSIVE_HASH_MAP_HEADER \ |
||||||
|
uint64_t IHM_key; \
|
||||||
|
struct hm_item *IHM_hash_link |
||||||
|
|
||||||
|
/* Index struct which acts as a pseudo-iterator within the hash map. */ |
||||||
|
typedef struct hm_index { |
||||||
|
uint32_t bucket_index; // hash map bucket index.
|
||||||
|
hm_item *item; // Pointer to hm_item within the hash map.
|
||||||
|
} hm_index; |
||||||
|
|
||||||
|
/* Returns true if two hm_indices point to the same object within the hash map
|
||||||
|
* and false otherwise. */ |
||||||
|
inline bool hm_index_compare(const hm_index *A, const hm_index *B) { |
||||||
|
return (A->item == B->item && A->bucket_index == B->bucket_index); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper functions for iterating over the hash map. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* On return idx will contain an invalid index which is always equal to
|
||||||
|
* hash_map->buckets.size_ */ |
||||||
|
void intrusive_hash_map_end(const intrusive_hash_map *hash_map, hm_index *idx); |
||||||
|
|
||||||
|
/* Iterates index to the next valid entry in the hash map and stores the
|
||||||
|
* index within idx. If end of table is reached, idx will contain the same |
||||||
|
* values as if intrusive_hash_map_end() was called. */ |
||||||
|
void intrusive_hash_map_next(const intrusive_hash_map *hash_map, hm_index *idx); |
||||||
|
|
||||||
|
/* On return, idx will contain the index of the first non-null entry in the hash
|
||||||
|
* map. If the hash map is empty, idx will contain the same values as if |
||||||
|
* intrusive_hash_map_end() was called. */ |
||||||
|
void intrusive_hash_map_begin(const intrusive_hash_map *hash_map, |
||||||
|
hm_index *idx); |
||||||
|
|
||||||
|
/* Initialize intrusive hash map data structure. This must be called before
|
||||||
|
* the hash map can be used. The initial size of an intrusive hash map will be |
||||||
|
* 2^initial_log2_map_size (valid range is [0, 31]). */ |
||||||
|
void intrusive_hash_map_init(intrusive_hash_map *hash_map, |
||||||
|
uint32_t initial_log2_map_size); |
||||||
|
|
||||||
|
/* Returns true if the hash map is empty and false otherwise. */ |
||||||
|
bool intrusive_hash_map_empty(const intrusive_hash_map *hash_map); |
||||||
|
|
||||||
|
/* Returns the number of elements currently in the hash map. */ |
||||||
|
size_t intrusive_hash_map_size(const intrusive_hash_map *hash_map); |
||||||
|
|
||||||
|
/* Find a hm_item within the hash map by key. Returns NULL if item was not
|
||||||
|
* found. */ |
||||||
|
hm_item *intrusive_hash_map_find(const intrusive_hash_map *hash_map, |
||||||
|
uint64_t key); |
||||||
|
|
||||||
|
/* Erase the hm_item that corresponds with key. If the hm_item is found, return
|
||||||
|
* the pointer to the hm_item. Else returns NULL. */ |
||||||
|
hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key); |
||||||
|
|
||||||
|
/* Attempts to insert a new hm_item into the hash map. If an element with the
|
||||||
|
* same key already exists, it will not insert the new item and return false. |
||||||
|
* Otherwise, it will insert the new item and return true. */ |
||||||
|
bool intrusive_hash_map_insert(intrusive_hash_map *hash_map, hm_item *item); |
||||||
|
|
||||||
|
/* Clears entire contents of the hash map, but leaves internal data structure
|
||||||
|
* untouched. Second argument takes a function pointer to a function that will |
||||||
|
* free the object designated by the user and pointed to by hash_map->value. */ |
||||||
|
void intrusive_hash_map_clear(intrusive_hash_map *hash_map, |
||||||
|
void (*free_object)(void *)); |
||||||
|
|
||||||
|
/* Erase all contents of hash map and free the memory. Hash map is invalid
|
||||||
|
* after calling this function and cannot be used until it has been |
||||||
|
* reinitialized (intrusive_hash_map_init()). This function takes a function |
||||||
|
* pointer to a function that will free the object designated by the user and |
||||||
|
* pointed to by hash_map->value. */ |
||||||
|
void intrusive_hash_map_free(intrusive_hash_map *hash_map, |
||||||
|
void (*free_object)(void *)); |
||||||
|
|
||||||
|
#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_H
|
@ -0,0 +1,46 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H |
||||||
|
#define GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/useful.h> |
||||||
|
#include <stdbool.h> |
||||||
|
|
||||||
|
/* The chunked vector is a data structure that allocates buckets for use in the
|
||||||
|
* hash map. ChunkedVector is logically equivalent to T*[N] (cast void* as |
||||||
|
* T*). It's internally implemented as an array of 1MB arrays to avoid |
||||||
|
* allocating large consecutive memory chunks. This is an internal data |
||||||
|
* structure that should never be accessed directly. */ |
||||||
|
typedef struct chunked_vector { |
||||||
|
size_t size_; |
||||||
|
void **first_; |
||||||
|
void ***rest_; |
||||||
|
} chunked_vector; |
||||||
|
|
||||||
|
/* Core intrusive hash map data structure. All internal elements are managed by
|
||||||
|
* functions and should not be altered manually. */ |
||||||
|
typedef struct intrusive_hash_map { |
||||||
|
uint32_t num_items; |
||||||
|
uint32_t extend_threshold; |
||||||
|
uint32_t log2_num_buckets; |
||||||
|
uint32_t hash_mask; |
||||||
|
chunked_vector buckets; |
||||||
|
} intrusive_hash_map; |
||||||
|
|
||||||
|
#endif // GRPC_CORE_EXT_CENSUS_INTRUSIVE_HASH_MAP_INTERNAL_H
|
@ -0,0 +1,282 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2017 Google Inc. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/ext/census/intrusive_hash_map.h" |
||||||
|
|
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/useful.h> |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
/* The initial size of an intrusive hash map will be 2 to this power. */ |
||||||
|
static const uint32_t kInitialLog2Size = 4; |
||||||
|
|
||||||
|
/* Simple object used for testing intrusive_hash_map. */ |
||||||
|
typedef struct object { uint64_t val; } object; |
||||||
|
|
||||||
|
/* Helper function to allocate and initialize object. */ |
||||||
|
static inline object *make_new_object(uint64_t val) { |
||||||
|
object *obj = (object *)gpr_malloc(sizeof(object)); |
||||||
|
obj->val = val; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
/* Wrapper struct for object. */ |
||||||
|
typedef struct ptr_item { |
||||||
|
INTRUSIVE_HASH_MAP_HEADER; |
||||||
|
object *obj; |
||||||
|
} ptr_item; |
||||||
|
|
||||||
|
/* Helper function that creates a new hash map item. It is up to the user to
|
||||||
|
* free the item that was allocated. */ |
||||||
|
static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { |
||||||
|
ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item)); |
||||||
|
new_item->IHM_key = key; |
||||||
|
new_item->IHM_hash_link = NULL; |
||||||
|
new_item->obj = make_new_object(value); |
||||||
|
return new_item; |
||||||
|
} |
||||||
|
|
||||||
|
/* Helper function to deallocate ptr_item. */ |
||||||
|
static void free_ptr_item(void *ptr) { gpr_free(((ptr_item *)ptr)->obj); } |
||||||
|
|
||||||
|
/* Simple string object used for testing intrusive_hash_map. */ |
||||||
|
typedef struct string_item { |
||||||
|
INTRUSIVE_HASH_MAP_HEADER; |
||||||
|
// User data.
|
||||||
|
char buf[32]; |
||||||
|
uint16_t len; |
||||||
|
} string_item; |
||||||
|
|
||||||
|
/* Helper function to allocate and initialize string object. */ |
||||||
|
static string_item *make_string_item(uint64_t key, const char *buf, |
||||||
|
uint16_t len) { |
||||||
|
string_item *item = (string_item *)gpr_malloc(sizeof(string_item)); |
||||||
|
item->IHM_key = key; |
||||||
|
item->IHM_hash_link = NULL; |
||||||
|
item->len = len; |
||||||
|
memcpy(item->buf, buf, sizeof(char) * len); |
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
/* Helper function for comparing two string objects. */ |
||||||
|
static bool compare_string_item(const string_item *A, const string_item *B) { |
||||||
|
if (A->IHM_key != B->IHM_key || A->len != B->len) |
||||||
|
return false; |
||||||
|
else { |
||||||
|
for (int i = 0; i < A->len; ++i) { |
||||||
|
if (A->buf[i] != B->buf[i]) return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
void test_empty() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); |
||||||
|
GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, NULL); |
||||||
|
} |
||||||
|
|
||||||
|
void test_single_item() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
|
||||||
|
ptr_item *new_item = make_ptr_item(10, 20); |
||||||
|
bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item); |
||||||
|
GPR_ASSERT(ok); |
||||||
|
|
||||||
|
ptr_item *item1 = |
||||||
|
(ptr_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10); |
||||||
|
GPR_ASSERT(item1->obj->val == 20); |
||||||
|
GPR_ASSERT(item1 == new_item); |
||||||
|
|
||||||
|
ptr_item *item2 = |
||||||
|
(ptr_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10); |
||||||
|
GPR_ASSERT(item2 == new_item); |
||||||
|
|
||||||
|
gpr_free(new_item->obj); |
||||||
|
gpr_free(new_item); |
||||||
|
GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, &free_ptr_item); |
||||||
|
} |
||||||
|
|
||||||
|
void test_two_items() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
|
||||||
|
string_item *new_item1 = make_string_item(10, "test1", 5); |
||||||
|
bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item1); |
||||||
|
GPR_ASSERT(ok); |
||||||
|
string_item *new_item2 = make_string_item(20, "test2", 5); |
||||||
|
ok = intrusive_hash_map_insert(&hash_map, (hm_item *)new_item2); |
||||||
|
GPR_ASSERT(ok); |
||||||
|
|
||||||
|
string_item *item1 = |
||||||
|
(string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)10); |
||||||
|
GPR_ASSERT(compare_string_item(new_item1, item1)); |
||||||
|
GPR_ASSERT(item1 == new_item1); |
||||||
|
string_item *item2 = |
||||||
|
(string_item *)intrusive_hash_map_find(&hash_map, (uint64_t)20); |
||||||
|
GPR_ASSERT(compare_string_item(new_item2, item2)); |
||||||
|
GPR_ASSERT(item2 == new_item2); |
||||||
|
|
||||||
|
item1 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)10); |
||||||
|
GPR_ASSERT(item1 == new_item1); |
||||||
|
item2 = (string_item *)intrusive_hash_map_erase(&hash_map, (uint64_t)20); |
||||||
|
GPR_ASSERT(item2 == new_item2); |
||||||
|
|
||||||
|
gpr_free(new_item1); |
||||||
|
gpr_free(new_item2); |
||||||
|
GPR_ASSERT(0 == intrusive_hash_map_size(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, NULL); |
||||||
|
} |
||||||
|
|
||||||
|
// Test resetting and clearing the hash map.
|
||||||
|
void test_reset_clear() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
|
||||||
|
// Add some data to the hash_map.
|
||||||
|
for (uint64_t i = 0; i < 3; ++i) { |
||||||
|
intrusive_hash_map_insert(&hash_map, (hm_item *)make_ptr_item(i, i)); |
||||||
|
} |
||||||
|
GPR_ASSERT(3 == intrusive_hash_map_size(&hash_map)); |
||||||
|
|
||||||
|
// Test find.
|
||||||
|
for (uint64_t i = 0; i < 3; ++i) { |
||||||
|
ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i); |
||||||
|
GPR_ASSERT(item != NULL); |
||||||
|
GPR_ASSERT(item->IHM_key == i && item->obj->val == i); |
||||||
|
} |
||||||
|
|
||||||
|
intrusive_hash_map_clear(&hash_map, &free_ptr_item); |
||||||
|
GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, &free_ptr_item); |
||||||
|
} |
||||||
|
|
||||||
|
// Check that the hash_map contains every key between [min_value, max_value]
|
||||||
|
// (inclusive).
|
||||||
|
void check_hash_map_values(intrusive_hash_map *hash_map, uint64_t min_value, |
||||||
|
uint64_t max_value) { |
||||||
|
GPR_ASSERT(intrusive_hash_map_size(hash_map) == max_value - min_value + 1); |
||||||
|
|
||||||
|
for (uint64_t i = min_value; i <= max_value; ++i) { |
||||||
|
ptr_item *item = (ptr_item *)intrusive_hash_map_find(hash_map, i); |
||||||
|
GPR_ASSERT(item != NULL); |
||||||
|
GPR_ASSERT(item->obj->val == i); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Add many items and cause the hash_map to extend.
|
||||||
|
void test_extend() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
|
||||||
|
const uint64_t kNumValues = (1 << 16); |
||||||
|
|
||||||
|
for (uint64_t i = 0; i < kNumValues; ++i) { |
||||||
|
ptr_item *item = make_ptr_item(i, i); |
||||||
|
bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item); |
||||||
|
GPR_ASSERT(ok); |
||||||
|
if (i % 1000 == 0) { |
||||||
|
check_hash_map_values(&hash_map, 0, i); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (uint64_t i = 0; i < kNumValues; ++i) { |
||||||
|
ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, i); |
||||||
|
GPR_ASSERT(item != NULL); |
||||||
|
GPR_ASSERT(item->IHM_key == i && item->obj->val == i); |
||||||
|
ptr_item *item2 = (ptr_item *)intrusive_hash_map_erase(&hash_map, i); |
||||||
|
GPR_ASSERT(item == item2); |
||||||
|
gpr_free(item->obj); |
||||||
|
gpr_free(item); |
||||||
|
} |
||||||
|
|
||||||
|
GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, &free_ptr_item); |
||||||
|
} |
||||||
|
|
||||||
|
void test_stress() { |
||||||
|
intrusive_hash_map hash_map; |
||||||
|
intrusive_hash_map_init(&hash_map, kInitialLog2Size); |
||||||
|
size_t n = 0; |
||||||
|
|
||||||
|
// Randomly add and insert entries 1000000 times.
|
||||||
|
for (uint64_t i = 0; i < 1000000; ++i) { |
||||||
|
int op = rand() & 0x1; |
||||||
|
|
||||||
|
switch (op) { |
||||||
|
// Case 0 is insertion of entry.
|
||||||
|
case 0: { |
||||||
|
uint64_t key = (uint64_t)(rand() % 10000); |
||||||
|
ptr_item *item = make_ptr_item(key, key); |
||||||
|
bool ok = intrusive_hash_map_insert(&hash_map, (hm_item *)item); |
||||||
|
if (ok) { |
||||||
|
n++; |
||||||
|
} else { |
||||||
|
gpr_free(item->obj); |
||||||
|
gpr_free(item); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
// Case 1 is removal of entry.
|
||||||
|
case 1: { |
||||||
|
uint64_t key = (uint64_t)(rand() % 10000); |
||||||
|
ptr_item *item = (ptr_item *)intrusive_hash_map_find(&hash_map, key); |
||||||
|
if (item != NULL) { |
||||||
|
n--; |
||||||
|
GPR_ASSERT(key == item->obj->val); |
||||||
|
ptr_item *item2 = |
||||||
|
(ptr_item *)intrusive_hash_map_erase(&hash_map, key); |
||||||
|
GPR_ASSERT(item == item2); |
||||||
|
gpr_free(item->obj); |
||||||
|
gpr_free(item); |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// Check size
|
||||||
|
GPR_ASSERT(n == intrusive_hash_map_size(&hash_map)); |
||||||
|
|
||||||
|
// Clean the hash_map up.
|
||||||
|
intrusive_hash_map_clear(&hash_map, &free_ptr_item); |
||||||
|
GPR_ASSERT(intrusive_hash_map_empty(&hash_map)); |
||||||
|
intrusive_hash_map_free(&hash_map, &free_ptr_item); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
gpr_time_init(); |
||||||
|
srand((unsigned)gpr_now(GPR_CLOCK_REALTIME).tv_nsec); |
||||||
|
|
||||||
|
test_empty(); |
||||||
|
test_single_item(); |
||||||
|
test_two_items(); |
||||||
|
test_reset_clear(); |
||||||
|
test_extend(); |
||||||
|
test_stress(); |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,199 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\1.0.204.1.props')" /> |
||||||
|
<ItemGroup Label="ProjectConfigurations"> |
||||||
|
<ProjectConfiguration Include="Debug|Win32"> |
||||||
|
<Configuration>Debug</Configuration> |
||||||
|
<Platform>Win32</Platform> |
||||||
|
</ProjectConfiguration> |
||||||
|
<ProjectConfiguration Include="Debug|x64"> |
||||||
|
<Configuration>Debug</Configuration> |
||||||
|
<Platform>x64</Platform> |
||||||
|
</ProjectConfiguration> |
||||||
|
<ProjectConfiguration Include="Release|Win32"> |
||||||
|
<Configuration>Release</Configuration> |
||||||
|
<Platform>Win32</Platform> |
||||||
|
</ProjectConfiguration> |
||||||
|
<ProjectConfiguration Include="Release|x64"> |
||||||
|
<Configuration>Release</Configuration> |
||||||
|
<Platform>x64</Platform> |
||||||
|
</ProjectConfiguration> |
||||||
|
</ItemGroup> |
||||||
|
<PropertyGroup Label="Globals"> |
||||||
|
<ProjectGuid>{BD364959-BDBF-ABD2-C6D1-FC838EBEBB60}</ProjectGuid> |
||||||
|
<IgnoreWarnIntDirInTempDetected>true</IgnoreWarnIntDirInTempDetected> |
||||||
|
<IntDir>$(SolutionDir)IntDir\$(MSBuildProjectName)\</IntDir> |
||||||
|
</PropertyGroup> |
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |
||||||
|
<PropertyGroup Condition="'$(VisualStudioVersion)' == '10.0'" Label="Configuration"> |
||||||
|
<PlatformToolset>v100</PlatformToolset> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(VisualStudioVersion)' == '11.0'" Label="Configuration"> |
||||||
|
<PlatformToolset>v110</PlatformToolset> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(VisualStudioVersion)' == '12.0'" Label="Configuration"> |
||||||
|
<PlatformToolset>v120</PlatformToolset> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(VisualStudioVersion)' == '14.0'" Label="Configuration"> |
||||||
|
<PlatformToolset>v140</PlatformToolset> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration"> |
||||||
|
<ConfigurationType>Application</ConfigurationType> |
||||||
|
<UseDebugLibraries>true</UseDebugLibraries> |
||||||
|
<CharacterSet>Unicode</CharacterSet> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration"> |
||||||
|
<ConfigurationType>Application</ConfigurationType> |
||||||
|
<UseDebugLibraries>false</UseDebugLibraries> |
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization> |
||||||
|
<CharacterSet>Unicode</CharacterSet> |
||||||
|
</PropertyGroup> |
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |
||||||
|
<ImportGroup Label="ExtensionSettings"> |
||||||
|
</ImportGroup> |
||||||
|
<ImportGroup Label="PropertySheets"> |
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\global.props" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\openssl.props" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\winsock.props" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\zlib.props" /> |
||||||
|
</ImportGroup> |
||||||
|
<PropertyGroup Label="UserMacros" /> |
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'"> |
||||||
|
<TargetName>census_intrusive_hash_map_test</TargetName> |
||||||
|
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> |
||||||
|
<Configuration-grpc_dependencies_zlib>Debug</Configuration-grpc_dependencies_zlib> |
||||||
|
<Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl> |
||||||
|
<Configuration-grpc_dependencies_openssl>Debug</Configuration-grpc_dependencies_openssl> |
||||||
|
</PropertyGroup> |
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Release'"> |
||||||
|
<TargetName>census_intrusive_hash_map_test</TargetName> |
||||||
|
<Linkage-grpc_dependencies_zlib>static</Linkage-grpc_dependencies_zlib> |
||||||
|
<Configuration-grpc_dependencies_zlib>Release</Configuration-grpc_dependencies_zlib> |
||||||
|
<Linkage-grpc_dependencies_openssl>static</Linkage-grpc_dependencies_openssl> |
||||||
|
<Configuration-grpc_dependencies_openssl>Release</Configuration-grpc_dependencies_openssl> |
||||||
|
</PropertyGroup> |
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |
||||||
|
<ClCompile> |
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||||
|
<WarningLevel>Level3</WarningLevel> |
||||||
|
<Optimization>Disabled</Optimization> |
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||||
|
<SDLCheck>true</SDLCheck> |
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
||||||
|
<TreatWarningAsError>true</TreatWarningAsError> |
||||||
|
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||||
|
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> |
||||||
|
</ClCompile> |
||||||
|
<Link> |
||||||
|
<SubSystem>Console</SubSystem> |
||||||
|
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||||
|
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||||
|
</Link> |
||||||
|
</ItemDefinitionGroup> |
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |
||||||
|
<ClCompile> |
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||||
|
<WarningLevel>Level3</WarningLevel> |
||||||
|
<Optimization>Disabled</Optimization> |
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||||
|
<SDLCheck>true</SDLCheck> |
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
||||||
|
<TreatWarningAsError>true</TreatWarningAsError> |
||||||
|
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||||
|
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> |
||||||
|
</ClCompile> |
||||||
|
<Link> |
||||||
|
<SubSystem>Console</SubSystem> |
||||||
|
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||||
|
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||||
|
</Link> |
||||||
|
</ItemDefinitionGroup> |
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
||||||
|
<ClCompile> |
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||||
|
<WarningLevel>Level3</WarningLevel> |
||||||
|
<Optimization>MaxSpeed</Optimization> |
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||||
|
<SDLCheck>true</SDLCheck> |
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
||||||
|
<TreatWarningAsError>true</TreatWarningAsError> |
||||||
|
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||||
|
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> |
||||||
|
</ClCompile> |
||||||
|
<Link> |
||||||
|
<SubSystem>Console</SubSystem> |
||||||
|
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||||
|
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||||
|
</Link> |
||||||
|
</ItemDefinitionGroup> |
||||||
|
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |
||||||
|
<ClCompile> |
||||||
|
<PrecompiledHeader>NotUsing</PrecompiledHeader> |
||||||
|
<WarningLevel>Level3</WarningLevel> |
||||||
|
<Optimization>MaxSpeed</Optimization> |
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking> |
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions> |
||||||
|
<SDLCheck>true</SDLCheck> |
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
||||||
|
<TreatWarningAsError>true</TreatWarningAsError> |
||||||
|
<DebugInformationFormat Condition="$(Jenkins)">None</DebugInformationFormat> |
||||||
|
<MinimalRebuild Condition="$(Jenkins)">false</MinimalRebuild> |
||||||
|
</ClCompile> |
||||||
|
<Link> |
||||||
|
<SubSystem>Console</SubSystem> |
||||||
|
<GenerateDebugInformation Condition="!$(Jenkins)">true</GenerateDebugInformation> |
||||||
|
<GenerateDebugInformation Condition="$(Jenkins)">false</GenerateDebugInformation> |
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding> |
||||||
|
<OptimizeReferences>true</OptimizeReferences> |
||||||
|
</Link> |
||||||
|
</ItemDefinitionGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<ClCompile Include="$(SolutionDir)\..\test\core\census\intrusive_hash_map_test.c"> |
||||||
|
</ClCompile> |
||||||
|
</ItemGroup> |
||||||
|
<ItemGroup> |
||||||
|
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc_test_util\grpc_test_util.vcxproj"> |
||||||
|
<Project>{17BCAFC0-5FDC-4C94-AEB9-95F3E220614B}</Project> |
||||||
|
</ProjectReference> |
||||||
|
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\grpc\grpc.vcxproj"> |
||||||
|
<Project>{29D16885-7228-4C31-81ED-5F9187C7F2A9}</Project> |
||||||
|
</ProjectReference> |
||||||
|
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr_test_util\gpr_test_util.vcxproj"> |
||||||
|
<Project>{EAB0A629-17A9-44DB-B5FF-E91A721FE037}</Project> |
||||||
|
</ProjectReference> |
||||||
|
<ProjectReference Include="$(SolutionDir)\..\vsprojects\vcxproj\.\gpr\gpr.vcxproj"> |
||||||
|
<Project>{B23D3D1A-9438-4EDA-BEB6-9A0A03D17792}</Project> |
||||||
|
</ProjectReference> |
||||||
|
</ItemGroup> |
||||||
|
<ItemGroup> |
||||||
|
<None Include="packages.config" /> |
||||||
|
</ItemGroup> |
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |
||||||
|
<ImportGroup Label="ExtensionTargets"> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies\grpc.dependencies.zlib.targets')" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> |
||||||
|
<Import Project="$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets" Condition="Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies\grpc.dependencies.openssl.targets')" /> |
||||||
|
</ImportGroup> |
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> |
||||||
|
<PropertyGroup> |
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> |
||||||
|
</PropertyGroup> |
||||||
|
<Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.redist.1.2.8.10\build\native\grpc.dependencies.zlib.redist.targets')" /> |
||||||
|
<Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.zlib.1.2.8.10\build\native\grpc.dependencies.zlib.targets')" /> |
||||||
|
<Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.redist.1.0.204.1\build\native\grpc.dependencies.openssl.redist.targets')" /> |
||||||
|
<Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.props')" /> |
||||||
|
<Error Condition="!Exists('$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\..\vsprojects\packages\grpc.dependencies.openssl.1.0.204.1\build\native\grpc.dependencies.openssl.targets')" /> |
||||||
|
</Target> |
||||||
|
</Project> |
||||||
|
|
@ -0,0 +1,21 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||||
|
<ItemGroup> |
||||||
|
<ClCompile Include="$(SolutionDir)\..\test\core\census\intrusive_hash_map_test.c"> |
||||||
|
<Filter>test\core\census</Filter> |
||||||
|
</ClCompile> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<Filter Include="test"> |
||||||
|
<UniqueIdentifier>{24bfacc6-bd89-4cdf-4183-3ff53180fa48}</UniqueIdentifier> |
||||||
|
</Filter> |
||||||
|
<Filter Include="test\core"> |
||||||
|
<UniqueIdentifier>{71b1debf-71c7-c1e9-9e01-21330ede0d7f}</UniqueIdentifier> |
||||||
|
</Filter> |
||||||
|
<Filter Include="test\core\census"> |
||||||
|
<UniqueIdentifier>{0228063a-a601-967e-27ed-9f6197cb3629}</UniqueIdentifier> |
||||||
|
</Filter> |
||||||
|
</ItemGroup> |
||||||
|
</Project> |
||||||
|
|
Loading…
Reference in new issue