You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
4.1 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#ifndef _PAGETABLE_H_
#define _PAGETABLE_H_
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
///////////////////////// Class Page //////////////////////////////////////////
template<typename Data_T,
const uint32_t _PageSizeBits,
const uint32_t _DataAlignment>
class Page
{
public:
static const uint32_t PAGE_SHIFT = _PageSizeBits;
static const uint32_t PAGE_SIZE = 1<<PAGE_SHIFT;
static const uint32_t ENTRIES = PAGE_SIZE/_DataAlignment;
static const uintptr_t PAGE_MASK = ~((uintptr_t)(PAGE_SIZE - 1));
static const uintptr_t OFFSET_MASK = (uintptr_t)(PAGE_SIZE - 1);
Data_T data[ENTRIES];
Page(uintptr_t _addr) :
addr(_addr),
valid(true)
{
memset(data, 0, sizeof(data));
}
static const uint32_t
getOffset(uintptr_t addr)
{
return (addr & OFFSET_MASK) / _DataAlignment;
}
uintptr_t addr;
bool valid;
};
///////////////////////// Class PageTable /////////////////////////////////////
template<typename Data_T,
const uint32_t _PageSizeBits,
const uint32_t _BucketsBits,
const uint32_t _DataAlignment>
class PageTable
{
public:
typedef Page<Data_T, _PageSizeBits, _DataAlignment> Page_T;
static const uint32_t BUCKETS = 1<<_BucketsBits;
static const uintptr_t BUCKET_MASK = BUCKETS - 1;
inline Page_T *get(uintptr_t addr)
{
uint32_t key = getKey(addr);
return buckets[key].get(addr);
}
inline Page_T *getFast(uintptr_t addr)
{
uint32_t key = getKey(addr);
return buckets[key].getFast();
}
PageTable()
{
Page_T *dummy = new Page_T(0);
if (dummy == NULL) {
perror(__FUNCTION__);
exit(EXIT_FAILURE);
}
dummy->valid = false;
for (uint32_t i = 0; i < BUCKETS; i++) {
buckets[i].setDummy(dummy);
}
}
static inline uint32_t
getKey(uintptr_t addr)
{
uint32_t ret = addr >> Page_T::PAGE_SHIFT;
// this branch should compile away on 32bit if PAGE_SHIFT == 16
// and BUCKETS == 16. if the page size is small, or the address
// space is big, we want to use the upper bits in the hash as well
if (Page_T::PAGE_SHIFT/8 < sizeof(ret)/2) {
// This produces the same code as >> 2*PAGE_SHIFT, but the
// compiler doesn't whine on 32bit.
addr >>= Page_T::PAGE_SHIFT;
ret ^= addr >> (Page_T::PAGE_SHIFT);
}
return ret & BUCKET_MASK;
}
///////////////////////// Class MRUVector ///////////////////////////////////
class MRUVector
{
public:
size_t size;
size_t maxSize;
Page_T **vec;
void growVec()
{
maxSize *= 2;
vec = (Page_T **)realloc(vec, maxSize * sizeof(Page_T *));
if (vec == NULL) {
perror(__FUNCTION__);
exit(EXIT_FAILURE);
}
for (size_t i = size; i < maxSize; i++) {
vec[i] = NULL;
}
}
Page_T *add(uintptr_t pageAddr)
{
Page_T *p;
if( (p = new Page_T(pageAddr)) == NULL ) {
perror(__FUNCTION__);
exit(EXIT_FAILURE);
}
if (size == maxSize) {
growVec();
}
vec[size++] = p;
return p;
}
public:
MRUVector() :
size(0),
maxSize(4),
vec(NULL)
{
growVec();
}
inline Page_T *
get(uintptr_t _addr)
{
uintptr_t pageAddr = _addr & Page_T::PAGE_MASK;
if( vec[0]->valid && vec[0]->addr == pageAddr ) {
return vec[0];
}
for (size_t i = 1; i < size; i++) {
if (vec[i]->addr == pageAddr) {
int newIndex = i / 2;
Page_T *tmp = vec[i];
vec[i] = vec[newIndex];
vec[newIndex] = tmp;
return tmp;
}
}
return add(pageAddr);
}
inline Page_T *
getFast()
{
return vec[0];
}
inline void
setDummy(Page_T *page)
{
vec[0] = page;
}
}; // MRUVector
MRUVector buckets[BUCKETS];
}; // HashTable
#endif