contributed by < shanshow
>
執行 make 時遇到問題
error ‘for’ loop initial declarations are only allowed in c99 mode in ubuntu
在 gcc 指定編譯參數
-std=c99
或-std=gnu99
(C99 with GNU extension) 即可。不全然是「老舊系統」,是相容性和預設組態議題
"jserv"
請您再重新檢視,並在中英文間以空白隔開
課程助教
根據作業的教學,執行
$ ./test_cpy
會得到
ternary_tree, loaded 259112 words in 0.151270 sec
Commands:
a add word to the tree
f find word in tree
s search words matching prefix
d delete word from the tree
q quit, freeing all data
choice:
根據老師在 facebook 上提供的zhanyangch共筆,可以得知在 choice:s 的情況下搜尋"A"會產生錯誤。
choice: s
find words matching prefix (at least 1 char): A
>Program received signal SIGSEGV, Segmentation fault.
0x0000000000401f8b in tst_suggest (p=0xd72680, c=65 'A', nchr=1,
a=0x7fffffffbd50, n=0x7fffffffbd0c, max=1024) at tst.c:330
330 a[(*n)++] = (char *) p->eqkid;
在tst.h中可找到介紹用法的註解
/** tst_search_prefix() fills ptr array 'a' with words prefixed with 's'.
* once the node containing the first prefix matching 's' is found
* tst_suggest() is called to traverse the ternary_tree beginning
* at the node filling 'a' with pointers to all words that contain
* the prefix upto 'max' words updating 'n' with the number of words
* in 'a'. a pointer to the first node is returned on success
* NULL otherwise.
*/
在tst.c中則可找到關於這函數 函式的用法
function 不做數學運算用途時,應該翻譯為「函式」
void tst_suggest(const tst_node *p,
const char c,
const size_t nchr,
char **a,
int *n,
const int max)
{
if (!p || *n == max)
return;
tst_suggest(p->lokid, c, nchr, a, n, max);
if (p->key)
tst_suggest(p->eqkid, c, nchr, a, n, max);
else if (*(((char *) p->eqkid) + nchr - 1) == c)
a[(*n)++] = (char *) p->eqkid;
tst_suggest(p->hikid, c, nchr, a, n, max);
}
(!p || *n >= max)
再次執行後,可以發現它搜索了前1024個前頭為A的單詞
suggest[1021] : Akzhal,
suggest[1022] : Alà
suggest[1023] : Alàs
suggest[1024] : Al
應該指出同學的名稱或 GitHub 代稱
"jserv"
作業中有提及,可從tst.h中的註解找到參考
/** tst_ins_del() ins/del copy or reference of 's' from ternary search tree.
* insert all nodes required for 's' in tree at eqkid node of leaf. if 'del'
* is non-zero deletes 's' from tree, otherwise insert 's' at node->eqkid
* with node->key set to the nul-chracter after final node in search path. if
* 'cpy' is non-zero allocate storage for 's', otherwise save pointer to 's'.
* if 's' already exists in tree, increment node->refcnt. (to be used for del).
* returns address of 's' in tree on successful insert (or on delete if refcnt
* non-zero), NULL on allocation failure on insert, or on successful removal
* of 's' from tree.
*/
void *tst_ins_del(tst_node **root,
char *const *s,
const int del,
const int CPY);
前往 tst.c 找尋 tst_ins_del()
void *tst_ins_del(tst_node **root, char *const *s, const int del, const int cpy)
{
/*......*/
if (*p++ == 0) {
if (cpy) { /* allocate storage for 's' */
const char *eqdata = strdup(*s);
if (!eqdata)
return NULL;
curr->eqkid = (tst_node *) eqdata;
return (void *) eqdata;
} else { /* save pointer to 's' (allocated elsewhere) */
curr->eqkid = (tst_node *) *s;
return (void *) *s;
}
}
/*......*/
}
參考共筆,在tst_ref.c中先劃好記憶體空間。
char (*city)[MAX] = malloc(sizeof (*city) * CMAX);
在更動途中遇到下列錯誤:
Segmentation fault (core dumped)
choice: q
*** Error in `./test_ref': free(): invalid pointer: 0x00007ffc11f6c1d0 ***
void tst_free_all(tst_node *p)
{
if (!p)
return;
tst_free_all(p->lokid);
if (p->key)
tst_free_all(p->eqkid);
tst_free_all(p->hikid);
if (!p->key)
free(p->eqkid);
free(p);
}
/** free the ternary search tree rooted at p, data storage external. */
void tst_free(tst_node *p)
{
if (!p)
return;
tst_free(p->lokid);
if (p->key)
tst_free(p->eqkid);
tst_free(p->hikid);
free(p);
}
*** Error in `./test_ref': free(): invalid pointer: 0x00007f05d09b4810 ***
static void *tst_del_word(tst_node **root,
tst_node *node,
tst_stack *stk,
const int freeword)
{
tst_node *victim = node; /* begin deletion w/victim */
tst_node *parent = tst_stack_pop(stk); /* parent to victim */
if (!victim->refcnt) { /* if last occurrence */
if (!victim->key && freeword) /* check key is nul */
free(victim->eqkid); /* free string (data) */
/*......*/
if (!victim->key && freeword) /* check key is nul */
free(victim->eqkid); /* free string (data) */
VS
if (!p->key)
free(p->eqkid);
註解寫明,如果最後的字串出現,會依照上列判斷式決定是否清除字串, CPY 模式下可以照常運作但是在 REF 狀態下會產生錯誤。
tst_del_word(root, curr, &stk, 1);
因此,在 tst.c 中,為了避免錯誤而又不讓 CPY 模式下的環境出現變化,將常數1的位置上填入 CPY ,如此一來 CPY 模式下能夠判斷為 TRUE ,而 REF 模式下能夠判斷為 FALSE 從而避免錯誤。
在 Makefile 內放入 bench
bench:
echo 3 | sudo tee /proc/sys/vm/drop_caches
perf stat --repeat 150 \
-e cache-misses,cache-references,instructions,cycles \
sudo ./test_cpy --bench
echo 3 | sudo tee /proc/sys/vm/drop_caches
perf stat --repeat 150 \
-e cache-misses,cache-references,instructions,cycles \
sudo ./test_ref --bench
「釋放所有 cache 記憶體空間」這段描述是錯誤的,請找 Linux 核心文件並修正
double bench(const tst_node *root,
char **a,
int *n,
const int max)
{
double t1, t2, ttime;
char word[]="A";
ttime = 0;
for (int i=0 ; i<25 ; i++) {
t1 = tvgetf();
tst_search_prefix(root, word, a, n, max);
t2 = tvgetf();
word[0]++;
ttime += t2 - t1;
}
word[0] = 'a';
for (int i=0 ; i<25 ; i++) {
t1 = tvgetf();
tst_search_prefix(root, word, a, n, max);
t2 = tvgetf();
word[0]++;
ttime += t2 - t1;
}
return ttime;
}
Performance counter stats for 'sudo ./test_cpy --bench' (150 runs):
2,025,944 cache-misses # 56.530 % of all cache refs ( +- 0.13% )
3,583,866 cache-references ( +- 0.11% )
544,523,831 instructions # 0.90 insn per cycle ( +- 0.01% )
604,969,702 cycles ( +- 0.15% )
0.191043196 seconds time elapsed ( +- 1.71% )
Performance counter stats for 'sudo ./test_ref --bench' (150 runs):
3,517,770 cache-misses # 65.822 % of all cache refs ( +- 0.33% )
5,344,407 cache-references ( +- 0.24% )
525,117,217 instructions # 0.76 insn per cycle ( +- 0.01% )
690,790,048 cycles ( +- 0.51% )
0.218351956 seconds time elapsed ( +- 1.50% )
build 速度
search 速度
原因 :
參考資料:
跟我一起写Makefile:MakeFile介绍
釋放Linux記憶體
linux 指令 - tee
在 Linux 中以特定的 CPU 核心執行程式
Linux的进程优先级
Linux 效能分析工具: Perf