libsvm代碼閱讀(3):關於Cache類的分析

下面來分析Cache類的源碼,該類位於svm.cpp中。這個類的主要功能是:負責運算所涉及的內存管理,包括申請、釋放等。web

簡單來講:這個Cache類,首先經過Cache構造函數申請一塊空間,這塊空間的大小是:L個head_t大小的空間。而後get_data函數保證結構head_t中至少有len個float的內存,而且將可使用的內存塊的指針放在data指針中;而swap_index函數則是用於交換head[i]和head[j]。app

Cache類的定義以下:函數

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  oop

<EMBED id=ZeroClipboardMovie_1 height=18 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">this

  1. class Cache  spa

  2. {  .net

  3. public:  指針

  4.     Cache(int l,long int size);  code

  5.     ~Cache();  orm

  6.   

  7.     // request data [0,len)  

  8.     // return some position p where [p,len) need to be filled  

  9.     // (p >= len if nothing needs to be filled)  

  10.     int get_data(const int index, Qfloat **data, int len);  

  11.     void swap_index(int i, int j);    

  12. private:  

  13.     int l;  

  14.     long int size;//所指定的所有內存,聽說用Mb作單位  

  15.     //結構head_t用來記錄所申請內存的指針,並記錄長度,並且經過雙向的指針,造成鏈表,增長尋址的速度  

  16.     struct head_t  

  17.     {  

  18.         head_t *prev, *next;    // a circular list是一個雙向鏈表,非循環鏈表  

  19.         Qfloat *data;  

  20.         int len;        // data[0,len) is cached in this entry  

  21.     };  

  22.   

  23.     head_t *head;//變量指針,該指針記錄程序中所申請的內存。  

  24.     head_t lru_head;//雙向鏈表的表頭  

  25.     void lru_delete(head_t *h);//從雙向鏈表中刪去某個元素的連接,通常是刪去當前所指向的元素  

  26.     void lru_insert(head_t *h);//在鏈表後面插入一個新的連接  

  27. };  

主要包含:

  1. 兩個int變量,分別是l和size,l是樣本個數,size是指定的所有內存;

  2. 一個構造函數Cache,該函數根據樣本數l申請L個head_t的空間;

  3. 一個析構函數~Cache,不用多說;

  4. 一個雙向鏈表的結構head_t;

  5. 一個get_data函數,具體下文再說;

  6. 一個swap_index函數,交換兩個head_t的值;

  7. 一個雙向鏈表的刪除函數lru_delete,一個插入函數lru_insert;

  8. 一個變量指針head,該指針指向程序中所申請的內存。

關於上面的結構體head_t,它是一個雙向鏈表方便先後內存的訪問,在文獻LIBSVM:A  Libray for SVM中以下說法:



構造函數的代碼以下:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_2 height=18 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. Cache::Cache(int l_,long int size_):l(l_),size(size_)  

  2. {  

  3.     //calloc函數的功能與malloc函數的功能類似,都是從堆分配內存該函數與malloc函數的一個顯著不一樣時  

  4.     //是,calloc函數獲得的內存空間是通過初始化的,其內容全爲0。  

  5.     head = (head_t *)calloc(l,sizeof(head_t));  // initialized to 0  

  6.     size /= sizeof(Qfloat);//先將原來byte數目轉化爲float的數目。  

  7.     size -= l * sizeof(head_t) / sizeof(Qfloat);//扣除掉L個head_t的內存數目  

  8.     size = max(size, 2 * (long int) l); // cache must be large enough for two columns  

  9.     lru_head.next = lru_head.prev = &lru_head;  

  10. }  

該函數根據實參:樣本數L,申請L個head_t的空間,初始化爲0;size的處理是:先將輸入的size值(byte單位)轉化爲float的數目,而後再減去L個head_t所佔的空間;其中lru_head由於尚沒有head_t中申請到內存,故雙向鏈表指向本身。

析構函數的代碼以下:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_3 height=18 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. Cache::~Cache()  

  2. {  

  3.     for(head_t *h = lru_head.next; h != &lru_head; h=h->next)  

  4.         free(h->data);  

  5.     free(head);  

  6. }  

這個很簡單,不用多說。


雙向鏈表的刪去函數代碼:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_4 height=18 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. void Cache::lru_delete(head_t *h)  

  2. {  

  3.     // delete from current location  

  4.     h->prev->next = h->next;  

  5.     h->next->prev = h->prev;  

  6. }  

該函數用於後面swap_index函數斷開雙向鏈表的實現。只是斷開連接,沒有刪去數據。


雙向鏈表的插入函數代碼:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_5 height=18 name=ZeroClipboardMovie_5 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=5&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. void Cache::lru_insert(head_t *h)  

  2. {  

  3.     // insert to last position  

  4.     h->next = &lru_head;  

  5.     h->prev = lru_head.prev;  

  6.     h->prev->next = h;  

  7.     h->next->prev = h;  

  8. }  

該函數用於後面swap_index函數恢復前面斷開鏈接的兩個數據的實現。


get_data函數的代碼:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_6 height=18 name=ZeroClipboardMovie_6 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=6&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. int Cache::get_data(const int index, Qfloat **data, int len)  

  2. {  

  3.     head_t *h = &head[index];  

  4.     if(h->len) lru_delete(h);  

  5.     int more = len - h->len;  

  6. <span style="white-space:pre">  </span>//由於shrink後h->len可能變小,那麼more>0,如今要作的就是從新filled,即把內存變成len那麼大(主要是經過realloc實現的)  

  7.     if(more > 0)  

  8.     {  

  9.         // free old space,這一步通常不會運行  

  10.         while(size < more)   //size爲所指定的所有內存  

  11.         {  

  12.             head_t *old = lru_head.next;  

  13.             lru_delete(old);  

  14.             free(old->data);  

  15.             size += old->len;  

  16.             old->data = 0;  

  17.             old->len = 0;  

  18.         }  

  19.   

  20.         // allocate new space  

  21.         h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len);//把內存擴大到len  

  22.         size -= more;  

  23.         swap(h->len,len);  

  24.     }  

  25.   

  26.     lru_insert(h);  

  27.     *data = h->data;  

  28.     return len;  

  29. }  

該函數主要的就是每一個head[i]具備len大小的內存空間。關於realloc函數是擴大內存用的。


swap_index函數的代碼:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_7 height=18 name=ZeroClipboardMovie_7 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=7&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. void Cache::swap_index(int i, int j)  

  2. {  

  3.     if(i==j) return;  

  4.   

  5.     if(head[i].len) lru_delete(&head[i]);//斷開雙向鏈表  

  6.     if(head[j].len) lru_delete(&head[j]);//斷開雙向鏈表  

  7.     swap(head[i].data,head[j].data);  

  8.     swap(head[i].len,head[j].len);  

  9.     if(head[i].len) lru_insert(&head[i]);  

  10.     if(head[j].len) lru_insert(&head[j]);  

  11.   

  12.     if(i>j) swap(i,j);  

  13.     for(head_t *h = lru_head.next; h!=&lru_head; h=h->next)  

  14.     {  

  15.         if(h->len > i)  

  16.         {  

  17.             if(h->len > j)  

  18.                 swap(h->data[i],h->data[j]);  

  19.             else  

  20.             {  

  21.                 // give up  

  22.                 lru_delete(h);  

  23.                 free(h->data);  

  24.                 size += h->len;  

  25.                 h->data = 0;  

  26.                 h->len = 0;  

  27.             }  

  28.         }  

  29.     }  

  30. }  

這個函數就是交換head_t[i]和head_t[j]的內容。首先將head_t[i]和head_t[j]從雙向鏈表中脫離出去,而後交換它們的內容,最後從新把它們恢復到鏈表中。

完整代碼以下:

[cpp]       view plain   copy   在CODE上查看代碼片   派生到個人代碼片  

<EMBED id=ZeroClipboardMovie_8 height=18 name=ZeroClipboardMovie_8 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer width=18 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=8&width=18&height=18" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">

  1. //  

  2. // Kernel Cache  

  3. //  

  4. // l is the number of total data items  

  5. // size is the cache size limit in bytes  

  6. //  

  7. //類Cache負責運算所涉及的內存的管理,包括申請、釋放等  

  8. class Cache  

  9. {  

  10. public:  

  11.     Cache(int l,long int size);  

  12.     ~Cache();  

  13.   

  14.     // request data [0,len)  

  15.     // return some position p where [p,len) need to be filled  

  16.     // (p >= len if nothing needs to be filled)  

  17.     int get_data(const int index, Qfloat **data, int len);  

  18.     void swap_index(int i, int j);    

  19. private:  

  20.     int l;  

  21.     long int size;//所指定的所有內存,聽說用Mb作單位  

  22.     //結構head_t用來記錄所申請內存的指針,並記錄長度,並且經過雙向的指針,造成鏈表,增長尋址的速度  

  23.     struct head_t  

  24.     {  

  25.         head_t *prev, *next;    // a circular list是一個雙向鏈表,非循環鏈表  

  26.         Qfloat *data;  

  27.         int len;        // data[0,len) is cached in this entry  

  28.     };  

  29.   

  30.     head_t *head;//變量指針,該指針記錄程序中所申請的內存。  

  31.     head_t lru_head;//雙向鏈表的表頭  

  32.     void lru_delete(head_t *h);//從雙向鏈表中刪去某個元素的連接,通常是刪去當前所指向的元素  

  33.     void lru_insert(head_t *h);//在鏈表後面插入一個新的連接  

  34. };  

  35.   

  36. Cache::Cache(int l_,long int size_):l(l_),size(size_)  

  37. {  

  38.     //calloc函數的功能與malloc函數的功能類似,都是從堆分配內存該函數與malloc函數的一個顯著不一樣時  

  39.     //是,calloc函數獲得的內存空間是通過初始化的,其內容全爲0。  

  40.     head = (head_t *)calloc(l,sizeof(head_t));  // initialized to 0  

  41.     size /= sizeof(Qfloat);//先將原來byte數目轉化爲float的數目。  

  42.     size -= l * sizeof(head_t) / sizeof(Qfloat);//扣除掉L個head_t的內存數目  

  43.     size = max(size, 2 * (long int) l); // cache must be large enough for two columns  

  44.     lru_head.next = lru_head.prev = &lru_head;  

  45. }  

  46.   

  47. Cache::~Cache()  

  48. {  

  49.     for(head_t *h = lru_head.next; h != &lru_head; h=h->next)  

  50.         free(h->data);  

  51.     free(head);  

  52. }  

  53.   

  54. void Cache::lru_delete(head_t *h)  

  55. {  

  56.     // delete from current location  

  57.     h->prev->next = h->next;  

  58.     h->next->prev = h->prev;  

  59. }  

  60.   

  61. void Cache::lru_insert(head_t *h)  

  62. {  

  63.     // insert to last position  

  64.     h->next = &lru_head;  

  65.     h->prev = lru_head.prev;  

  66.     h->prev->next = h;  

  67.     h->next->prev = h;  

  68. }  

  69.   

  70. //該函數保證head_t[index]中至少有len個float的內存,而且將可使用的內存塊的指針放在data指針中,返回值爲申請到的內存  

  71. int Cache::get_data(const int index, Qfloat **data, int len)  

  72. {  

  73.     head_t *h = &head[index];  

  74.     if(h->len) lru_delete(h);  

  75.     int more = len - h->len;  

  76.   

  77.     if(more > 0)  

  78.     {  

  79.         // free old space  

  80.         while(size < more)   //size爲所指定的所有內存  

  81.         {  

  82.             head_t *old = lru_head.next;  

  83.             lru_delete(old);  

  84.             free(old->data);  

  85.             size += old->len;  

  86.             old->data = 0;  

  87.             old->len = 0;  

  88.         }  

  89.   

  90.         // allocate new space  

  91.         h->data = (Qfloat *)realloc(h->data,sizeof(Qfloat)*len);  

  92.         size -= more;  

  93.         swap(h->len,len);  

  94.     }  

  95.   

  96.     lru_insert(h);  

  97.     *data = h->data;  

  98.     return len;  

  99. }  

  100.   

  101. void Cache::swap_index(int i, int j)  

  102. {  

  103.     if(i==j) return;  

  104.   

  105.     if(head[i].len) lru_delete(&head[i]);//斷開雙向鏈表  

  106.     if(head[j].len) lru_delete(&head[j]);//斷開雙向鏈表  

  107.     swap(head[i].data,head[j].data);  

  108.     swap(head[i].len,head[j].len);  

  109.     if(head[i].len) lru_insert(&head[i]);  

  110.     if(head[j].len) lru_insert(&head[j]);  

  111.   

  112.     if(i>j) swap(i,j);  

  113.     for(head_t *h = lru_head.next; h!=&lru_head; h=h->next)  

  114.     {  

  115.         if(h->len > i)  

  116.         {  

  117.             if(h->len > j)  

  118.                 swap(h->data[i],h->data[j]);  

  119.             else  

  120.             {  

  121.                 // give up  

  122.                 lru_delete(h);  

  123.                 free(h->data);  

  124.                 size += h->len;  

  125.                 h->data = 0;  

  126.                 h->len = 0;  

  127.             }  

  128.         }  

  129.     }  

  130. }  

相關文章
相關標籤/搜索