Skip to content

Commit a0ed67b

Browse files
committed
Use kernel memory allocation to allocate array
- Use the math relation between golden ratio and Fibonacci to estimate size - Immediately return when memory allocation fails
1 parent 54c2c70 commit a0ed67b

File tree

4 files changed

+285
-131
lines changed

4 files changed

+285
-131
lines changed

client.c

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,61 +6,12 @@
66
#include <unistd.h>
77

88
#define FIB_DEV "/dev/fibonacci"
9-
#define FIBSIZE 256
109
#define BUFFSIZE 2500
11-
12-
#define BIGNSIZE 12
13-
14-
typedef struct BigN {
15-
unsigned long long cell[BIGNSIZE];
16-
} ubig;
17-
18-
/**
19-
* fib_to_string() - Convert the k-th Fibonacci number into string.
20-
* @buf: Buffer where the resulting string will be stored.
21-
* @buf_sz: Size of the buffer.
22-
* @fib: Pointer to the Fibonacci number data.
23-
* @fib_sz: Size of the Fibonacci number data (unused in this implementation).
24-
*
25-
* Return: The start position (offset) of the @fib string, which is always 0
26-
* in this implementation.
27-
*/
28-
int fib_to_string(char *buf, int buf_sz, void *fib, int fib_sz)
29-
{
30-
const ubig *f = (ubig *) fib;
31-
32-
memset(buf, '0', buf_sz);
33-
buf[buf_sz - 1] = '\0';
34-
int index = BIGNSIZE - 1;
35-
while (index >= 0 && !f->cell[index])
36-
index--;
37-
if (index == -1) {
38-
return buf_sz - 2;
39-
}
40-
41-
for (int i = index; i >= 0; i--) {
42-
for (unsigned long long mask = 0x8000000000000000ULL; mask;
43-
mask >>= 1) {
44-
int carry = ((f->cell[i] & mask) != 0);
45-
for (int j = buf_sz - 2; j >= 0; j--) {
46-
buf[j] += buf[j] - '0' + carry;
47-
carry = (buf[j] > '9');
48-
if (carry)
49-
buf[j] -= 10;
50-
}
51-
}
52-
}
53-
54-
int offset = 0;
55-
while (buf[offset] == '0')
56-
offset++;
57-
return (buf[offset] == '\0') ? (offset - 1) : offset;
58-
}
10+
#define FIBSIZE 256
5911

6012
int main()
6113
{
62-
char buf[FIBSIZE];
63-
char str_buf[BUFFSIZE];
14+
char buf[BUFFSIZE];
6415
int N = 300; /* TODO: try test something bigger than the limit */
6516

6617
int fd = open(FIB_DEV, O_RDWR);
@@ -71,15 +22,14 @@ int main()
7122

7223
for (int i = 0; i <= N; i++) {
7324
lseek(fd, i, SEEK_SET);
74-
long long sz = read(fd, buf, FIBSIZE);
75-
if (sz < 0) {
25+
long long sz = read(fd, buf, BUFFSIZE);
26+
if (sz <= 0) {
7627
printf("Error reading from " FIB_DEV " at offset %d.\n", i);
7728
} else {
78-
int __offset = fib_to_string(str_buf, BUFFSIZE, (void *) buf, sz);
7929
printf("Reading from " FIB_DEV
8030
" at offset %d, returned the sequence "
8131
"%s.\n",
82-
i, str_buf + __offset);
32+
i, buf);
8333
}
8434
}
8535

fibdrv.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@
1010
#include <linux/version.h>
1111

1212
/* Method 1: use unsigned long long array to store big number. */
13-
#include "lib/adding.h"
13+
// #include "lib/adding.h"
1414

1515
/* Method 2: introduce fast-doubling */
16-
// #include "lib/fast_doubling.h"
16+
#include "lib/fast_doubling.h"
1717

1818
MODULE_LICENSE("Dual MIT/GPL");
1919
MODULE_AUTHOR("National Cheng Kung University, Taiwan");
2020
MODULE_DESCRIPTION("Fibonacci engine driver");
2121
MODULE_VERSION("0.1");
2222

23-
#define MAX_LENGTH 1093
23+
#define MAX_LENGTH 188795
2424
#define DEV_FIBONACCI_NAME "fibonacci"
25+
#define BUFFSIZE 2500
2526

2627
static dev_t fib_dev = 0;
2728
static struct class *fib_class;
@@ -49,9 +50,17 @@ static ssize_t fib_read(struct file *file,
4950
size_t size,
5051
loff_t *offset)
5152
{
52-
struct BigN fib = fib_sequence(*offset);
53-
copy_to_user(buf, &fib, sizeof(fib));
54-
return sizeof(fib);
53+
struct BigN *fib = fib_sequence(*offset);
54+
if (!fib) { // fail to calculate fib k
55+
copy_to_user(buf, "", 1);
56+
return 0;
57+
}
58+
59+
char fib_buf[BUFFSIZE];
60+
int __offset = fib_to_string(fib_buf, BUFFSIZE, fib);
61+
copy_to_user(buf, fib_buf + __offset, BUFFSIZE - __offset);
62+
destroy_ubig(fib);
63+
return BUFFSIZE - __offset;
5564
}
5665

5766
/* write operation is skipped */

lib/adding.h

Lines changed: 116 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,148 @@
1-
#include <linux/kernel.h>
1+
#include <linux/slab.h>
22
#include <linux/string.h>
33

4-
#define BIGNSIZE 12
4+
static inline int estimate_size(long long k)
5+
{
6+
if (k <= 93)
7+
return 1;
8+
unsigned long long n = (k * 20899 - 34950) / 1926610;
9+
return (int) n + 1;
10+
}
511

612
typedef struct BigN {
7-
unsigned long long cell[BIGNSIZE];
13+
int size;
14+
unsigned long long *cell;
815
} ubig;
916

10-
static inline void init_ubig(ubig *x)
17+
ubig *new_ubig(int size)
1118
{
12-
for (int i = 0; i < BIGNSIZE; x->cell[i++] = 0)
13-
;
19+
ubig *ptr = (ubig *) kmalloc(sizeof(ubig), GFP_KERNEL);
20+
if (!ptr)
21+
return (ubig *) NULL;
22+
23+
unsigned long long *ullptr = (unsigned long long *) kmalloc(
24+
size * sizeof(unsigned long long), GFP_KERNEL);
25+
if (!ullptr) {
26+
kfree(ptr);
27+
return (ubig *) NULL;
28+
}
29+
memset(ullptr, 0, size * sizeof(unsigned long long));
30+
31+
ptr->size = size;
32+
ptr->cell = ullptr;
33+
return ptr;
34+
}
35+
36+
static inline void destroy_ubig(ubig *ptr)
37+
{
38+
if (ptr) {
39+
if (ptr->cell)
40+
kfree(ptr->cell);
41+
kfree(ptr);
42+
}
43+
}
44+
45+
static inline void zero_ubig(ubig *x)
46+
{
47+
memset(x->cell, 0, x->size * sizeof(unsigned long long));
48+
}
49+
50+
static inline void ubig_assign(ubig *dest, ubig *src)
51+
{
52+
memcpy(dest->cell, src->cell, dest->size * sizeof(unsigned long long));
1453
}
1554

16-
/**
17-
* ubig_add() - Add two large unsigned integers.
18-
* @dest: Pointer to the destination ubig where the result will be stored.
19-
* @a: Pointer to the first ubig.
20-
* @b: Pointer to the second ubig.
21-
*
22-
* This function performs addition of two large unsigned integers represented by
23-
* the `ubig` structures pointed to by @a and @b. The result of the addition is
24-
* stored in the `ubig` structure pointed to by @dest.
25-
*/
2655
static inline void ubig_add(ubig *dest, ubig *a, ubig *b)
2756
{
28-
for (int i = 0; i < BIGNSIZE; i++)
57+
for (int i = 0; i < a->size; i++)
2958
dest->cell[i] = a->cell[i] + b->cell[i];
3059

31-
for (int i = 0; i < BIGNSIZE - 1; i++)
60+
for (int i = 0; i < a->size - 1; i++)
3261
dest->cell[i + 1] += (dest->cell[i] < a->cell[i]);
3362
}
3463

64+
static inline void ubig_sub(ubig *dest, ubig *a, ubig *b)
65+
{
66+
for (int i = 0; i < a->size; i++)
67+
dest->cell[i] = a->cell[i] - b->cell[i];
68+
69+
for (int i = 0; i < a->size - 1; i++)
70+
dest->cell[i + 1] -= (dest->cell[i] > a->cell[i]);
71+
}
72+
3573
/**
3674
* fib_sequence() - Calculate the k-th Fibonacci number.
3775
* @k: Index of the Fibonacci number to calculate.
3876
*
3977
* Return: The k-th Fibonacci number on success.
4078
*/
41-
static ubig fib_sequence(long long k)
79+
static ubig *fib_sequence(long long k)
4280
{
4381
if (k <= 1LL) {
44-
ubig result;
45-
init_ubig(&result);
46-
result.cell[0] = (unsigned long long) k;
47-
return result;
82+
ubig *ret = new_ubig(1);
83+
if (!ret)
84+
return (ubig *) NULL;
85+
ret->cell[0] = (unsigned long long) k;
86+
return ret;
4887
}
4988

50-
ubig a, b, c;
51-
init_ubig(&a);
52-
init_ubig(&b);
53-
b.cell[0] = 1ULL;
89+
int sz = estimate_size(k);
90+
ubig *a = new_ubig(sz);
91+
ubig *b = new_ubig(sz);
92+
ubig *c = new_ubig(sz);
93+
if (!a || !b || !c) {
94+
destroy_ubig(a);
95+
destroy_ubig(b);
96+
destroy_ubig(c);
97+
return (ubig *) NULL;
98+
}
5499

100+
b->cell[0] = 1ULL;
55101
for (int i = 2; i <= k; i++) {
56-
ubig_add(&c, &a, &b);
57-
a = b;
58-
b = c;
102+
ubig_add(c, a, b);
103+
ubig_assign(a, b);
104+
ubig_assign(b, c);
59105
}
60106

107+
destroy_ubig(a);
108+
destroy_ubig(b);
61109
return c;
62110
}
111+
112+
/**
113+
* fib_to_string() - Convert the k-th Fibonacci number into string.
114+
* @buf: Buffer where the resulting string will be stored.
115+
* @buf_sz: Size of the buffer.
116+
* @fib: Pointer to the Fibonacci number data.
117+
*
118+
* Return: The start position (offset) of the @fib string.
119+
*/
120+
int fib_to_string(char *buf, int buf_sz, ubig *fib)
121+
{
122+
memset(buf, '0', buf_sz);
123+
buf[buf_sz - 1] = '\0';
124+
int index = fib->size - 1;
125+
while (index >= 0 && !fib->cell[index])
126+
index--;
127+
if (index == -1) {
128+
return buf_sz - 2;
129+
}
130+
131+
for (int i = index; i >= 0; i--) {
132+
for (unsigned long long mask = 0x8000000000000000ULL; mask;
133+
mask >>= 1) {
134+
int carry = ((fib->cell[i] & mask) != 0);
135+
for (int j = buf_sz - 2; j >= 0; j--) {
136+
buf[j] += buf[j] - '0' + carry;
137+
carry = (buf[j] > '9');
138+
if (carry)
139+
buf[j] -= 10;
140+
}
141+
}
142+
}
143+
144+
int offset = 0;
145+
while (buf[offset] == '0')
146+
offset++;
147+
return (buf[offset] == '\0') ? (offset - 1) : offset;
148+
}

0 commit comments

Comments
 (0)