Skip to content

Commit 7728eaa

Browse files
TheJStoneapanda
authored andcommitted
Extended Utility Codel (#475)
1 parent 6ae2c56 commit 7728eaa

5 files changed

Lines changed: 94 additions & 5 deletions

File tree

core/utils/codel.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
#include <cmath>
55
#include <deque>
6+
#include <functional>
67

78
#include <glog/logging.h>
89

910
#include "time.h"
1011
#include "queue.h"
1112

12-
1313
namespace bess {
1414
namespace utils {
1515
// Codel(Controlled Delay Management) is an Queue controller based on this
@@ -50,6 +50,7 @@ class Codel final: public Queue<T> {
5050
queue_(),
5151
drop_func_(drop_func) { }
5252

53+
// deconstructor that drops all objects still left in the internal queue.
5354
virtual ~Codel() {
5455
Wrapper w;
5556
while (!queue_.empty()) {
@@ -134,8 +135,15 @@ class Codel final: public Queue<T> {
134135
}
135136
return i;
136137
}
137-
138-
size_t Capacity() override { return queue_.max_size(); }
138+
// the underlying queue is deque which is a dynamically sized queue with a max size
139+
// determined by system limit. Therefore, the capacity is a specified value used to
140+
// limit the queue or if no value is specified, the queue's system limit.
141+
size_t Capacity() override {
142+
if (max_size_ != 0) {
143+
return max_size_;
144+
}
145+
return queue_.max_size();
146+
}
139147

140148
bool Empty() override { return queue_.empty(); }
141149

@@ -147,6 +155,21 @@ class Codel final: public Queue<T> {
147155
}
148156

149157
size_t Size() override { return queue_.size(); }
158+
159+
// The undelying queue is deque which is a dynamically sized queue with a max size
160+
// determined by system limits. Therefore, the resize method will error if the new_capacity
161+
// is outside of the queue's system limits or otherwise, only change the imposed limit on
162+
// the capacity of the queue.
163+
int Resize(size_t new_capacity) override {
164+
if (new_capacity <= Size()) {
165+
return -1;
166+
} else if (new_capacity >= queue_.max_size()) {
167+
return -1;
168+
}
169+
170+
max_size_ = new_capacity;
171+
return 0;
172+
}
150173

151174
private:
152175
// Calls the drop_func on the object if the drop function exists

core/utils/codel_test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace {
99

1010
using bess::utils::Codel;
11+
using bess::utils::Queue;
1112
void integer_drop(int* ptr) {
1213
delete ptr;
1314
}
@@ -226,7 +227,7 @@ TEST(CodelTest, MultiPushPop) {
226227
EXPECT_EQ(c.Size(), n);
227228

228229
int** output = new int*[n];
229-
c.Pop(output, n);
230+
ASSERT_EQ(c.Pop(output, n), n);
230231
for (int i = 0; i < n; i++) {
231232
ASSERT_EQ(output[i], vals[i]);
232233
}

core/utils/llqueue_test.cc

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace {
66

77
using bess::utils::LockLessQueue;
8+
using bess::utils::Queue;
89

910
// Simple test to make sure one can get back out object
1011
TEST(LLQueueTest, SingleInputOutput) {
@@ -53,6 +54,39 @@ TEST(LLQueueTest, MultiInputOutput) {
5354
}
5455
}
5556

57+
// simple test to make sure that the queue is resized properly
58+
TEST(LLQueueTest, Resize) {
59+
LockLessQueue<int*> q(8);
60+
61+
int n = 6;
62+
int* vals1[n];
63+
int* vals2[n];
64+
for (int i = 0; i < n; i++) {
65+
vals1[i] = new int();
66+
vals2[i] = new int();
67+
}
68+
ASSERT_EQ(q.Push(vals1, n), n);
69+
EXPECT_EQ(q.Size(), n);
70+
71+
ASSERT_EQ(q.Resize(16), 0);
72+
ASSERT_EQ(q.Capacity(), 16);
73+
ASSERT_EQ(q.Push(vals2, n), n);
74+
ASSERT_EQ(q.Size(), 2 * n);
75+
76+
int** output = new int*[2*n];
77+
ASSERT_EQ(q.Pop(output, 2 * n), 2*n);
78+
for (int i = 0; i < n; i++) {
79+
ASSERT_EQ(output[i], vals1[i]);
80+
ASSERT_EQ(output[i + n], vals2[i]);
81+
}
82+
83+
for (int i = 0; i < n; i++) {
84+
delete vals1[i];
85+
delete vals2[i];
86+
}
87+
delete[] output;
88+
}
89+
5690
// simple test to make sure that multiple objects can be enqueued and dequeued
5791
// at the same time
5892
TEST(LLQueueTest, MultiPushPop) {
@@ -66,7 +100,7 @@ TEST(LLQueueTest, MultiPushPop) {
66100
EXPECT_EQ(q.Size(), n);
67101

68102
int** output = new int*[n];
69-
q.Pop(output, n);
103+
ASSERT_EQ(q.Pop(output, n), n);
70104
for (int i = 0; i < n; i++) {
71105
ASSERT_EQ(output[i], vals[i]);
72106
}

core/utils/lock_less_queue.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,33 @@ class LockLessQueue final : public Queue<T> {
7373
bool Empty() override { return llring_empty(ring_); }
7474

7575
bool Full() override { return llring_full(ring_); }
76+
77+
int Resize(size_t new_capacity) override {
78+
if (new_capacity <= Size() || (new_capacity & (new_capacity - 1))) {
79+
return -1;
80+
}
81+
82+
int err;
83+
size_t ring_sz = llring_bytes_with_slots(new_capacity);
84+
llring* new_ring = reinterpret_cast<struct llring*>(malloc(ring_sz));
85+
CHECK(new_ring);
86+
err = llring_init(new_ring, new_capacity, ring_->common.sp_enqueue,
87+
ring_->common.sc_dequeue);
88+
if (err != 0) {
89+
free(new_ring);
90+
return err;
91+
}
92+
93+
void* obj;
94+
while (llring_dequeue(ring_, reinterpret_cast<void**>(&obj)) == 0) {
95+
llring_enqueue(new_ring, obj);
96+
}
97+
98+
free(ring_);
99+
ring_ = new_ring;
100+
capacity_ = new_capacity;
101+
return 0;
102+
}
76103

77104
private:
78105
struct llring* ring_; // class's ring buffer

core/utils/queue.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ class Queue {
3939

4040
// Returns true if full and false otherwise
4141
virtual bool Full() = 0;
42+
43+
// Resizes the queue to the specified new capacity which must be larger than
44+
// the current size. Returns 0 on success.
45+
virtual int Resize(size_t) = 0;
4246
};
4347

4448
} // namespace utils

0 commit comments

Comments
 (0)