Skip to content

Commit

Permalink
Add Makefil and benchmark.cr
Browse files Browse the repository at this point in the history
  • Loading branch information
greyblake committed Jul 9, 2016
1 parent 366b8f6 commit 0428260
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
# Dependencies will be locked in application that uses them
/shard.lock

/tmp/*
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CRYSTAL_BIN ?= $(shell which crystal)

benchmark:
$$(mkdir tmp -p)
$(CRYSTAL_BIN) build --release -o tmp/benchmark ./benchmark.cr $(CRFLAGS)
tmp/benchmark
test:
$(CRYSTAL_BIN) spec
54 changes: 39 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,64 @@
# kiwi
# Kiwi

TODO: Write a description here
A unified interface for Key/Value storages. Implemented in Crystal.

## Installation


Add this to your application's `shard.yml`:

```yaml
dependencies:
kiwi:
github: greyblake/kiwi
github: greyblake/crystal-kiwi
```
## Usage
### MemoryStore
```crystal
require "kiwi"
require "kiwi/memory_store"

store = Kiwi::MemoryStore.new

store.set("key", "value")
store.get("key") # => "value"
store.delete("key")
store.clear
```

### FileStore

TODO: Write usage instructions here
```crystal
require "kiwi/file_store"
## Development
store = Kiwi::FileStore(dir: "/tmp/kiwi")
```

TODO: Write development instructions here
### RedisStore

## Contributing
RedisStore requires you to have [https://github.com/stefanwille/crystal-redis](redis shard).

1. Fork it ( https://github.com/greyblake/kiwi/fork )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull Request
```crystal
require "redis"
require "kiwi/redis_store"
store = Kiwi::RedisStore(redis: Redis.new)
```

## Performance porn

Results can vary on different systems depending on hardware(CPU, RAM, HDD/SSD) and software(OS, file system, etc).
Ops/sec.

```
| | set | get | delete |
| --------------- | ------- | ------- | -------- |
| **MemoryStore** | 4740000 | 8607000 | 35602000 |
| **FileStore** | 19000 | 29000 | 7000 |
| **RedisStore** | 44000 | 45000 | 23000 |
```

## Contributors

Expand Down
92 changes: 92 additions & 0 deletions benchmark.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
require "./src/kiwi"

N = 100_000

def benchmark(name)
start_time = Time.now
yield
writing_time = Time.now - start_time
speed = (N.to_f / writing_time.to_f)
rounded_speed = ((speed / 1000).round * 1000).to_i
puts " #{name}: #{rounded_speed} ops/sec"
rounded_speed
end

def gen_data
data = Hash(String, String).new
N.times do |i|
key = "key-#{i.to_s}"
value = "value-#{i.to_s}"
data[key] = value
end
data
end

stores = Array(Kiwi::Store).new
stores << Kiwi::MemoryStore.new
stores << Kiwi::FileStore.new(dir: "/tmp/kiwi_test")
stores << Kiwi::RedisStore.new(redis: Redis.new)


def measure(stores)
data = gen_data
result = Hash(String, Hash(String, Int32)).new

stores.each do |store|
puts store.class
store_metrics = Hash(String, Int32).new

store_metrics["set"] = benchmark("#set") do
data.each do |key, val|
store.set(key, val)
end
end

store_metrics["get"] = benchmark("#get") do
data.each do |key, val|
store.get(key)
end
end

store_metrics["delete"] = benchmark("#delete") do
data.each do |key, val|
store.delete(key)
end
end

store.clear
store_name = store.class.to_s.split("::").last
result[store_name] = store_metrics
end
result
end

def print_table(result)
store_col_size = result.keys.map(&.size).max
set_col_size = result.values.map { |metrics| metrics["set"].to_s.size }.max
get_col_size = result.values.map { |metrics| metrics["get"].to_s.size }.max
delete_col_size = result.values.map { |metrics| metrics["delete"].to_s.size }.max

# header
puts "| " + " " * store_col_size + " | " + "set".ljust(set_col_size) + " | " + "get".ljust(get_col_size) + " | " + "delete".ljust(delete_col_size) + " |"
puts "| " + "-" * store_col_size + " | " + "-" * set_col_size + " | " + "-" * get_col_size + " | " + "-" * delete_col_size + " |"

# rows
result.each do |store, metrics|
print "| "
print store.ljust(store_col_size)
print " | "
print metrics["set"].to_s.rjust(set_col_size)
print " | "
print metrics["get"].to_s.rjust(get_col_size)
print " | "
print metrics["delete"].to_s.rjust(delete_col_size)
puts " |"
end
end

puts
result = measure(stores)
puts "\n"
print_table(result)
puts "\n"
1 change: 1 addition & 0 deletions src/kiwi.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ require "./kiwi/store"
require "./kiwi/*"

module Kiwi
VERSION = "0.1.0"
end
1 change: 1 addition & 0 deletions src/kiwi/file_store.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "./store"
require "digest/sha1"
require "file_utils"

Expand Down
6 changes: 2 additions & 4 deletions src/kiwi/memory_store.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "./store"

module Kiwi
class MemoryStore < Store
def initialize
Expand All @@ -8,10 +10,6 @@ module Kiwi
@mem[key]?
end

#def has?(key)
# !!(@mem[key]?)
#end

def set(key, val)
@mem[key] = val
end
Expand Down
1 change: 1 addition & 0 deletions src/kiwi/redis_store.cr
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "./store"
require "redis"

module Kiwi
Expand Down
3 changes: 0 additions & 3 deletions src/kiwi/version.cr

This file was deleted.

0 comments on commit 0428260

Please sign in to comment.