Skip to content

Commit

Permalink
Implement Popcount support (#1)
Browse files Browse the repository at this point in the history
* Try popcount

* update

* Module optimizer

* Add popcount support
  • Loading branch information
fsaintjacques committed Apr 21, 2020
1 parent 9d0d21a commit 6b48fc1
Show file tree
Hide file tree
Showing 11 changed files with 516 additions and 132 deletions.
131 changes: 131 additions & 0 deletions include/jitmap/container/container.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2020 RStudio, Inc. All rights reserved.
//
// 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:https://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.

#pragma once

#include <bitset>
#include <cstddef>
#include <cstdint>
#include <optional>

#include <jitmap/size.h>

namespace jitmap {

enum ContainerType : uint8_t {
BITMAP = 0,
ARRAY = 1,
RUN_LENGTH = 2,
EMPTY = 3,
FULL = 4,
};

constexpr size_t kBitsInProxy = 64U;
using ProxyBitmap = std::bitset<kBitsInProxy>;

class Statistics {
public:
Statistics() : Statistics(0UL, 0L) {}
Statistics(ProxyBitmap proxy, int32_t count)
: proxy_(std::move(proxy)), count_(count) {}

static Statistics Empty() {
return Statistics(0xFFFFFFFFFFFFFFFFULL, kBitsPerContainer);
}
static Statistics Full() { return Statistics(); };

bool all() const noexcept { return count_ == kBitsPerContainer; }
bool full() const noexcept { return all(); }

bool any() const noexcept { return proxy_.any(); }

bool none() const noexcept { return proxy_.none(); }
bool empty() const noexcept { return none(); }

private:
ProxyBitmap proxy_;
int32_t count_ = 0UL;
};

class Container {
public:
using index_type = uint16_t;

Container() : statistics_(std::nullopt) {}
Container(Statistics statistics) : statistics_(std::move(statistics)) {}

size_t count() const noexcept { return statistics().all(); }

bool all() const noexcept { return count() == kBitsPerContainer; }
bool full() const noexcept { return all(); }

bool any() const noexcept { return statistics().any(); }

bool none() const noexcept { return statistics().none(); }
bool empty() const noexcept { return none(); }

bool has_statistics() const noexcept { return statistics_.has_value(); }
const Statistics& statistics() const noexcept {
if (!has_statistics()) statistics_ = ComputeStatistics();
return statistics_.value();
};

virtual bool operator[](index_type index) const noexcept = 0;

private:
virtual Statistics ComputeStatistics() const noexcept = 0;

// Field is mutable because it is lazily computed.
mutable std::optional<Statistics> statistics_;
};

class EmptyContainer final : public Container {
public:
bool operator[](index_type index) const noexcept final { return false; }

private:
Statistics ComputeStatistics() const noexcept final { return Statistics::Empty(); }
};

class FullContainer final : public Container {
public:
bool operator[](index_type index) const noexcept final { return true; }

private:
Statistics ComputeStatistics() const noexcept final { return Statistics::Full(); }
};

template <typename EffectiveType, ContainerType Type>
class BaseContainer : public Container {
public:
using SelfType = EffectiveType;
static constexpr ContainerType type = Type;

constexpr ContainerType container_type() const { return type; }
};

using DenseBitset = std::bitset<kBitsPerContainer>;

class DenseContainer final : public BaseContainer<DenseContainer, BITMAP> {
bool operator[](index_type index) const noexcept { return bitmap_[index]; }

private:
Statistics ComputeStatistics() const noexcept final {
return {0, static_cast<uint16_t>(bitmap_.count())};
}

DenseBitset bitmap_;
};

}; // namespace jitmap
2 changes: 2 additions & 0 deletions include/jitmap/query/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class CompilerException : public Exception {

// Signature of generated functions
typedef void (*DenseEvalFn)(const char**, char*);
typedef int32_t (*DenseEvalPopCountFn)(const char**, char*);

struct CompilerOptions {
// Controls LLVM optimization level (-O0, -O1, -O2, -O3). Anything above 3
Expand Down Expand Up @@ -97,6 +98,7 @@ class JitEngine : util::Pimpl<JitEngineImpl> {

// Lookup a query
DenseEvalFn LookupUserQuery(const std::string& query_name);
DenseEvalPopCountFn LookupUserPopCountQuery(const std::string& query_name);

// Return the LLVM name for the host CPU.
//
Expand Down
21 changes: 16 additions & 5 deletions include/jitmap/query/query.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ class EvaluationContext;

class QueryImpl;

constexpr int64_t kUnknownPopCount = -1;

class Query : util::Pimpl<QueryImpl> {
public:
// Create a new query object based on an expression.
Expand All @@ -54,9 +56,11 @@ class Query : util::Pimpl<QueryImpl> {
// Evaluate the expression on dense bitmaps.
//
// \param[in] ctx, evaluation context, see `EvaluationContext`.
// \param[in] inputs, pointers to input bitmaps, see further note on ordering.
// \param[out] output, pointer where the resulting bitmap will be written to,
// must not be nullptr.
// \param[in] ins, pointers to input bitmaps, see further note on ordering.
// \param[out] out, pointer where the resulting bitmap will be written to,
// must not be nullptr.
// \return kUnknownPopCount if popcount is not computed, else the popcount of
// the resulting bitmap.
//
// \throws Exception if any of the inputs/output pointers are nullptr.
//
Expand All @@ -76,8 +80,11 @@ class Query : util::Pimpl<QueryImpl> {
// auto ordered_bitmaps = ReorderInputs({"a": a, "b": b, "c": c}, order);
// query->Eval(ordered_bitmaps, output);
// ```
void Eval(const EvaluationContext& ctx, std::vector<const char*> inputs, char* output);
void Eval(std::vector<const char*> inputs, char* output);
int32_t Eval(const EvaluationContext& ctx, std::vector<const char*> ins, char* out);
int32_t Eval(std::vector<const char*> ins, char* out);

int32_t EvalUnsafe(const EvaluationContext& ctx, std::vector<const char*>& ins,
char* out);

// Return the referenced variables and the expected order.o
//
Expand Down Expand Up @@ -129,8 +136,12 @@ class EvaluationContext {
MissingPolicy missing_policy() const { return missing_policy_; }
void set_missing_policy(MissingPolicy policy) { missing_policy_ = policy; }

bool popcount() const { return popcount_; }
void set_popcount(bool popcount) { popcount_ = popcount; }

private:
MissingPolicy missing_policy_ = ERROR;
bool popcount_ = false;
};

} // namespace query
Expand Down
36 changes: 36 additions & 0 deletions include/jitmap/util/aligned.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 RStudio, Inc. All rights reserved.
//
// 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:https://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.

#pragma once

#include <array>

#include <jitmap/size.h>

namespace jitmap {

template <typename T, size_t N, size_t Alignment = kCacheLineSize>
struct alignas(Alignment) aligned_array : public std::array<T, N> {
// Change the default constructor to zero initialize the data storage.
aligned_array() {
T zero{};
std::fill(this->begin(), this->end(), zero);
}

explicit aligned_array(T val) {
std::fill(this->begin(), this->end(), val);
}
};

} // namespace jitmap
Loading

0 comments on commit 6b48fc1

Please sign in to comment.