<div>
<br>
</div>
<div><div><br></div><div>-- </div><div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:14px;font-variant-ligatures:normal;background-color:rgb(255,255,255)">Best regards </div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:14px;font-variant-ligatures:normal;background-color:rgb(255,255,255)">Eli</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:14px;font-variant-ligatures:normal;background-color:rgb(255,255,255)"><br></div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:14px;font-variant-ligatures:normal;background-color:rgb(255,255,255)">天涯无处不重逢</div><div style="color:rgb(34,34,34);font-family:arial,sans-serif;font-size:14px;font-variant-ligatures:normal;background-color:rgb(255,255,255)"><span style="color:rgb(0,0,0);font-family:"Microsoft YaHei",Verdana,arial,sans-serif">a leaf duckweed belongs to the sea, where not to meet in life </span></div></div><div>Sent with <a href="http://www.sparrowmailapp.com/?sig" target="_blank">Sparrow</a></div><div><br></div></div>
<p style="color:#a0a0a8">On Friday, 17 February 2017 at 1:03 AM, Martin Kletzander wrote:</p><blockquote type="cite"><div>
<span><div><div><div>On Thu, Feb 16, 2017 at 05:35:12PM +0800, Eli Qiao wrote:</div><blockquote type="cite"><div><div>This patch adds some utils struct and functions to expose resctrl</div><div>information.</div></div></blockquote><div><br></div><div>One tiny nitpick, but it might actually help you as well. You can use</div><div>-v7 parameter to git send-email or git format-patch to automatically add</div><div>'v7' to the subject-prefix keeping the "PATCH" in there. Not only could</div><div>this be easier for you, but people like me, who filter patches and other</div><div>mails on the list to different folders, would have these properly</div><div>categorized.</div><div><br></div><div>Anyway, for the review now.</div></div></div></span></div></blockquote><div><br></div><div>Thx </div><blockquote type="cite"><div><span><div><div><div><br></div><blockquote type="cite"><div><div>virResCtrlAvailable: If resctrl interface exist on host</div><div>virResCtrlGet: get specify type resource contral information</div></div></blockquote><div><br></div><div>"get specific resource control information" ???</div></div></div></span></div></blockquote><div><br></div><div>Yep </div><blockquote type="cite"><div><span><div><div><div><br></div><blockquote type="cite"><div><div>virResCtrlInit: initialize resctrl struct from the host's sys fs.</div><div>resctrlall[]: an array to maintain resource control information.</div><div><br></div><div>Signed-off-by: Eli Qiao <<a href="mailto:liyong.qiao@intel.com" target="_blank">liyong.qiao@intel.com</a>></div><div>---</div><div>include/libvirt/virterror.h | 1 +</div><div>po/<a href="http://POTFILES.in" target="_blank">POTFILES.in</a> | 1 +</div><div>src/<a href="http://Makefile.am" target="_blank">Makefile.am</a> | 1 +</div><div>src/libvirt_private.syms | 4 +</div><div>src/util/virerror.c | 1 +</div><div>src/util/virresctrl.c | 343 ++++++++++++++++++++++++++++++<wbr>++++++++++++++</div><div>src/util/virresctrl.h | 80 +++++++++++</div><div>7 files changed, 431 insertions(+)</div><div>create mode 100644 src/util/virresctrl.c</div><div>create mode 100644 src/util/virresctrl.h</div><div><br></div><div>diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c</div><div>new file mode 100644</div><div>index 0000000..80481bc</div><div>--- /dev/null</div><div>+++ b/src/util/virresctrl.c</div><div>@@ -0,0 +1,343 @@</div><div>+/*</div><div>+ * virresctrl.c: methods for managing resource contral</div><div>+ *</div><div>+ * This library is free software; you can redistribute it and/or</div><div>+ * modify it under the terms of the GNU Lesser General Public</div><div>+ * License as published by the Free Software Foundation; either</div><div>+ * version 2.1 of the License, or (at your option) any later version.</div><div>+ *</div><div>+ * This library is distributed in the hope that it will be useful,</div><div>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU</div><div>+ * Lesser General Public License for more details.</div><div>+ *</div><div>+ * You should have received a copy of the GNU Lesser General Public</div><div>+ * License along with this library. If not, see</div><div>+ * <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>><wbr>.</div><div>+ *</div><div>+ * Authors:</div><div>+ * Eli Qiao <<a href="mailto:liyong.qiao@intel.com" target="_blank">liyong.qiao@intel.com</a>></div><div>+ */</div><div>+#include <config.h></div><div>+</div><div>+#include <sys/ioctl.h></div><div>+#if defined HAVE_SYS_SYSCALL_H</div><div>+# include <sys/syscall.h></div></div></blockquote><div><br></div><div>What do you need syscall.h for?</div></div></div></span></div></blockquote><div>Removed</div><div> </div><blockquote type="cite"><div><span><div><div><div><br></div><blockquote type="cite"><div><div>+#endif</div><div>+#include <sys/types.h></div><div>+#include <sys/stat.h></div><div>+#include <fcntl.h></div><div>+</div><div>+#include "virresctrl.h"</div><div>+#include "viralloc.h"</div><div>+#include "virerror.h"</div><div>+#include "virfile.h"</div><div>+#include "virhostcpu.h"</div><div>+#include "virlog.h"</div><div>+#include "virstring.h"</div><div>+#include "nodeinfo.h"</div><div>+</div><div>+VIR_LOG_INIT("util.resctrl");</div><div>+</div><div>+#define VIR_FROM_THIS VIR_FROM_RESCTRL</div><div>+</div><div>+#define RESCTRL_DIR "/sys/fs/resctrl"</div><div>+#define RESCTRL_INFO_DIR "/sys/fs/resctrl/info"</div><div>+#define SYSFS_SYSTEM_PATH "/sys/devices/system"</div><div>+</div></div></blockquote><div><br></div><div>If you need SYSFS_..._PATH for anything, it probably could be split into</div><div>other src/util/ files. Example below.</div><div><br></div><blockquote type="cite"><div><div>+#define MAX_CPU_SOCKET_NUM 8</div><div>+#define MAX_CBM_BIT_LEN 32</div><div>+#define MAX_SCHEMATA_LEN 1024</div><div>+#define MAX_FILE_LEN ( 10 * 1024 * 1024)</div><div>+</div><div>+</div><div>+static unsigned int host_id;</div><div>+</div><div>+static virResCtrl resctrlall[] = {</div><div>+ {</div><div>+ .name = "L3",</div><div>+ .cache_level = "l3",</div><div>+ },</div><div>+ {</div><div>+ .name = "L3DATA",</div><div>+ .cache_level = "l3",</div><div>+ },</div><div>+ {</div><div>+ .name = "L3CODE",</div><div>+ .cache_level = "l3",</div><div>+ },</div><div>+ {</div><div>+ .name = "L2",</div><div>+ .cache_level = "l2",</div><div>+ },</div><div>+};</div><div>+</div><div>+static int virResCtrlGetInfoStr(const int type, const char *item, char **str)</div><div>+{</div><div>+ int ret = 0;</div><div>+ char *tmp;</div><div>+ char *path;</div><div>+</div><div>+ if (virAsprintf(&path, "%s/%s/%s", RESCTRL_INFO_DIR, resctrlall[type].name, item) < 0)</div><div>+ return -1;</div><div>+ if (virFileReadAll(path, 10, str) < 0) {</div><div>+ ret = -1;</div><div>+ goto cleanup;</div><div>+ }</div><div>+</div><div>+ if ((tmp = strchr(*str, '\n'))) *tmp = '\0';</div><div>+</div><div>+ cleanup:</div><div>+ VIR_FREE(path);</div><div>+ return ret;</div><div>+}</div><div>+</div><div>+</div><div>+static int virResCtrlGetCPUValue(const char *path, char **value)</div></div></blockquote><div><br></div><div>It would be more consistent if you reused parts of virHostCPUGetValue(),</div><div>put them in a function, and use that one in both this one an the</div><div>original one. It chould be also put in the virhostcpu.c since that's</div><div>about the host cpu.</div><div><br></div></div></div></span></div></blockquote><div>Done </div><blockquote type="cite"><div><span><div><div><blockquote type="cite"><div>+static int virResctrlGetCPUSocketID(const size_t cpu, int *socket_id)</div></blockquote><div><br></div><div>No need for this function, just use virHostCPUParseSocket()</div><div><br></div></div></div></span></div></blockquote><div>virHostCPUParseSocket is a static function, I created a new one. </div><blockquote type="cite"><div><span><div><div><blockquote type="cite"><div>+static int virResCtrlGetCPUCache(const size_t cpu, int type, int *cache)</div></blockquote><div><br></div><div>So we have some places in the code that get info from sysfs. I</div><div>understand that cache is controlled in the resctrl, but one doesn't have</div><div>to have resctrl to get some cache info, so I would move this function</div><div>into virhostcpu.c and keep here only the stuff strictly related to</div><div>resource control.</div></div></div></span></div></blockquote><div>Done </div><blockquote type="cite"><div><span><div><div><div><br></div><blockquote type="cite"><div><div>+{</div><div>+ int ret = -1;</div><div>+ char *cache_dir = NULL;</div><div>+ char *cache_str = NULL;</div><div>+ char *tmp;</div><div>+ int carry = -1;</div><div>+</div><div>+ if (virAsprintf(&cache_dir,</div><div>+ "%s/cpu/cpu%zu/cache/index%d/<wbr>size",</div><div>+ SYSFS_SYSTEM_PATH, cpu, type) < 0)</div><div>+ return -1;</div><div>+</div><div>+ if (virResCtrlGetCPUValue(cache_<wbr>dir, &cache_str) < 0)</div><div>+ goto cleanup;</div><div>+</div><div>+ tmp = cache_str;</div><div>+</div><div>+ while (*tmp != '\0') tmp++;</div><div>+</div><div>+ if (*(tmp - 1) == 'K') {</div><div>+ *(tmp - 1) = '\0';</div><div>+ carry = 1;</div><div>+ } else if (*(tmp - 1) == 'M') {</div><div>+ *(tmp - 1) = '\0';</div><div>+ carry = 1024;</div><div>+ }</div><div>+</div><div>+ if (virStrToLong_i(cache_str, NULL, 0, cache) < 0)</div><div>+ goto cleanup;</div><div>+</div><div>+ *cache = (*cache) * carry;</div><div>+</div><div>+ if (*cache < 0)</div><div>+ goto cleanup;</div><div>+</div><div>+ ret = 0;</div><div>+ cleanup:</div><div>+ VIR_FREE(cache_dir);</div><div>+ VIR_FREE(cache_str);</div><div>+ return ret;</div><div>+}</div><div>+</div></div></blockquote><div><br></div><div>Why all this fuzz? You should instead pass pointer to virStrToLong_i to</div><div>get where the number ends and then use virScaleInteger() to multiply it</div><div>properly.</div><div><br></div></div></div></span></div></blockquote><div>Good to know, thx. done. </div><blockquote type="cite"><div><span><div><div><blockquote type="cite"><div><div>+/* Fill all cache bank informations */</div><div>+static virResCacheBankPtr virResCtrlGetCacheBanks(int type, int *n_sockets)</div><div>+{</div></div></blockquote><div><br></div><div>Still could be in virhostcpu.c</div></div></div></span></div></blockquote><div><br></div><div>okay, will move it to there. </div><blockquote type="cite"><div><span><div><div><div><br></div><blockquote type="cite"><div><div>+ int npresent_cpus;</div><div>+ int idx = -1;</div><div>+ size_t i;</div><div>+ virResCacheBankPtr bank;</div><div>+</div><div>+ *n_sockets = 1;</div><div>+ if ((npresent_cpus = virHostCPUGetCount()) < 0)</div><div>+ return NULL;</div><div>+</div><div>+ if (type == VIR_RDT_RESOURCE_L3</div><div>+ || type == VIR_RDT_RESOURCE_L3DATA</div><div>+ || type == VIR_RDT_RESOURCE_L3CODE)</div><div>+ idx = 3;</div><div>+ else if (type == VIR_RDT_RESOURCE_L2)</div><div>+ idx = 2;</div><div>+</div><div>+ if (idx == -1)</div><div>+ return NULL;</div><div>+</div></div></blockquote><div><br></div><div>Indentation, "||" should be on the previous line but, most importantly,</div><div>why not switch? That'd make sure you won't miss any enum value and if</div><div>someone adds a new one, compilator will see it's missing here.</div><div><br></div></div></div></span></div></blockquote><div>Done </div><blockquote type="cite"><div><span><div><div><blockquote type="cite"><div><div>+ if (VIR_ALLOC_N(bank, *n_sockets) < 0) {</div><div>+ *n_sockets = 0;</div></div></blockquote><div><br></div><div>set this before the first return so that this function guarantees</div><div>n_sockets to be 0 on fail. Moreover, n_sockets is always set to 1</div><div>here. Due to the way the rest of the function is designed, this doesn't</div><div>have to be here at all.</div><div><br></div></div></div></span></div></blockquote><div>Done. </div><blockquote type="cite"><div><span><div><div><blockquote type="cite"><div><div>+ return NULL;</div><div>+ }</div><div>+</div><div>+ for (i = 0; i < npresent_cpus; i ++) {</div><div>+ int s_id;</div><div>+ int cache_size;</div><div>+</div><div>+ if (virResctrlGetCPUSocketID(i, &s_id) < 0)</div><div>+ goto error;</div><div>+</div><div>+ if (s_id > (*n_sockets - 1)) {</div><div>+ size_t cur = *n_sockets;</div><div>+ size_t exp = s_id - (*n_sockets) + 1;</div><div>+ if (VIR_EXPAND_N(bank, cur, exp) < 0)</div><div>+ goto error;</div><div>+ *n_sockets = s_id + 1;</div><div>+ }</div><div>+</div><div>+ if (bank[s_id].cpu_mask == NULL) {</div><div>+ if (!(bank[s_id].cpu_mask = virBitmapNew(npresent_cpus)))</div><div>+ goto error;</div><div>+ }</div><div>+</div><div>+ ignore_value(virBitmapSetBit(<wbr>bank[s_id].cpu_mask, i));</div><div>+</div><div>+ if (bank[s_id].cache_size == 0) {</div><div>+ if (virResCtrlGetCPUCache(i, idx, &cache_size) < 0)</div><div>+ goto error;</div><div>+</div><div>+ bank[s_id].cache_size = cache_size;</div><div>+ bank[s_id].cache_min = cache_size / resctrlall[type].cbm_len;</div><div>+ }</div><div>+ }</div><div>+ return bank;</div><div>+</div></div></blockquote><div><br></div><div>Wouldn't it be easier to have list of virResCacheBankPtr *banks; and</div><div>size_t nbanks; and then just populate each pointer when that socket is</div><div>on the system, so that you that NULL means the socket info was not</div><div>filled yet. Or just a list that isn't sparse (like yours is now). The</div><div>logic here seems hard to read.</div><div><br></div></div></div></span></div></blockquote><div>:( sorry, I don’t get you </div><div> </div><div> Are you saying pre-allocate memory for virResCacheBankPtr? here nbanks are equal to sockets.</div><div><br></div><div>I can not know how many nbanks(sockets) on the host before virResCtrlGetCacheBanks.</div><div><br></div><div>can you show me some code examples?</div><div><br></div><blockquote type="cite"><div><span><div><div><div>I'll continue the review tomorrow.</div><div><br></div><div>Martin</div><div><br></div><blockquote type="cite"><div><div>+ error:</div><div>+ *n_sockets = 0;</div><div>+ VIR_FREE(bank);</div><div>+ return NULL;</div><div>+}</div><div>+</div><div>+static int virResCtrlGetConfig(int type)</div><div>+{</div><div>+ int ret;</div><div>+ size_t i;</div><div>+ char *str;</div><div>+</div><div>+ /* Read min_cbm_bits from resctrl.</div><div>+ eg: /sys/fs/resctrl/info/L3/num_<wbr>closids</div><div>+ */</div><div>+ if ((ret = virResCtrlGetInfoStr(type, "num_closids", &str)) < 0)</div><div>+ return ret;</div><div>+</div><div>+ if (virStrToLong_i(str, NULL, 10, &resctrlall[type].num_closid) < 0)</div><div>+ return -1;</div><div>+</div><div>+ VIR_FREE(str);</div><div>+</div><div>+ /* Read min_cbm_bits from resctrl.</div><div>+ eg: /sys/fs/resctrl/info/L3/cbm_<wbr>mask</div><div>+ */</div><div>+ if ((ret = virResCtrlGetInfoStr(type, "min_cbm_bits", &str)) < 0)</div><div>+ return ret;</div><div>+</div><div>+ if (virStrToLong_i(str, NULL, 10, &resctrlall[type].min_cbm_<wbr>bits) < 0)</div><div>+ return -1;</div><div>+</div><div>+ VIR_FREE(str);</div><div>+</div><div>+ /* Read cbm_mask string from resctrl.</div><div>+ eg: /sys/fs/resctrl/info/L3/cbm_<wbr>mask</div><div>+ */</div><div>+ if ((ret = virResCtrlGetInfoStr(type, "cbm_mask", &str)) < 0)</div><div>+ return ret;</div><div>+</div><div>+ /* Calculate cbm length from the default cbm_mask. */</div><div>+ resctrlall[type].cbm_len = strlen(str) * 4;</div><div>+ VIR_FREE(str);</div><div>+</div><div>+ /* Get all cache bank informations */</div><div>+ resctrlall[type].cache_banks = virResCtrlGetCacheBanks(type,</div><div>+ &(resctrlall[type].num_banks))<wbr>;</div><div>+</div><div>+ if (resctrlall[type].cache_banks == NULL)</div><div>+ return -1;</div><div>+</div><div>+ for (i = 0; i < resctrlall[type].num_banks; i++) {</div><div>+ /*L3CODE and L3DATA shares same L3 resource, so they should</div><div>+ * have same host_id. */</div><div>+ if (type == VIR_RDT_RESOURCE_L3CODE)</div><div>+ resctrlall[type].cache_banks[<wbr>i].host_id = resctrlall[VIR_RDT_RESOURCE_<wbr>L3DATA].cache_banks[i].host_<wbr>id;</div><div>+ else</div><div>+ resctrlall[type].cache_banks[<wbr>i].host_id = host_id++;</div><div>+ }</div><div>+</div><div>+ resctrlall[type].enabled = true;</div><div>+</div><div>+ return ret;</div><div>+}</div><div>+</div><div>+int</div><div>+virResCtrlInit(void)</div><div>+{</div><div>+ size_t i = 0;</div><div>+ char *tmp;</div><div>+ int rc = 0;</div><div>+</div><div>+ for (i = 0; i < VIR_RDT_RESOURCE_LAST; i++) {</div><div>+ if ((rc = virAsprintf(&tmp, "%s/%s", RESCTRL_INFO_DIR, resctrlall[i].name)) < 0) {</div><div>+ VIR_ERROR(_("Failed to initialize resource control config"));</div><div>+ return -1;</div><div>+ }</div><div>+ if (virFileExists(tmp)) {</div><div>+ if ((rc = virResCtrlGetConfig(i)) < 0)</div><div>+ VIR_ERROR(_("Failed to get resource control config"));</div><div>+ return -1;</div><div>+ }</div><div>+</div><div>+ VIR_FREE(tmp);</div><div>+ }</div><div>+ return rc;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * Test whether the host support resource control</div><div>+ */</div><div>+bool</div><div>+virResCtrlAvailable(void)</div><div>+{</div><div>+ if (!virFileExists(RESCTRL_INFO_<wbr>DIR))</div><div>+ return false;</div><div>+ return true;</div><div>+}</div><div>+</div><div>+/*</div><div>+ * Return an virResCtrlPtr point to virResCtrl object,</div><div>+ * We should not modify it out side of virresctrl.c</div><div>+ */</div><div>+virResCtrlPtr</div><div>+virResCtrlGet(int type)</div><div>+{</div><div>+ return &resctrlall[type];</div><div>+}</div><div>diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h</div><div>new file mode 100644</div><div>index 0000000..aa113f4</div><div>--- /dev/null</div><div>+++ b/src/util/virresctrl.h</div><div>@@ -0,0 +1,80 @@</div><div>+/*</div><div>+ * * virresctrl.h: methods for managing rscctrl</div><div>+ * *</div><div>+ * * Copyright (C) 2016 Intel, Inc.</div><div>+ * *</div><div>+ * * This library is free software; you can redistribute it and/or</div><div>+ * * modify it under the terms of the GNU Lesser General Public</div><div>+ * * License as published by the Free Software Foundation; either</div><div>+ * * version 2.1 of the License, or (at your option) any later version.</div><div>+ *</div><div>+ * This library is distributed in the hope that it will be useful,</div><div>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU</div><div>+ * Lesser General Public License for more details.</div><div>+ *</div><div>+ * You should have received a copy of the GNU Lesser General Public</div><div>+ * License along with this library. If not, see</div><div>+ * <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>><wbr>.</div><div>+ *</div><div>+ * Authors:</div><div>+ * Eli Qiao <<a href="mailto:liyong.qiao@intel.com" target="_blank">liyong.qiao@intel.com</a>></div><div>+ */</div><div>+</div><div>+#ifndef __VIR_RESCTRL_H__</div><div>+# define __VIR_RESCTRL_H__</div><div>+</div><div>+# include "virutil.h"</div><div>+# include "virbitmap.h"</div><div>+</div><div>+enum {</div><div>+ VIR_RDT_RESOURCE_L3,</div><div>+ VIR_RDT_RESOURCE_L3DATA,</div><div>+ VIR_RDT_RESOURCE_L3CODE,</div><div>+ VIR_RDT_RESOURCE_L2,</div><div>+ /* Must be the last */</div><div>+ VIR_RDT_RESOURCE_LAST,</div><div>+};</div><div>+</div><div>+</div><div>+typedef struct _virResCacheBank virResCacheBank;</div><div>+typedef virResCacheBank *virResCacheBankPtr;</div><div>+struct _virResCacheBank {</div><div>+ unsigned int host_id;</div><div>+ unsigned long long cache_size;</div><div>+ unsigned long long cache_left;</div><div>+ unsigned long long cache_min;</div><div>+ virBitmapPtr cpu_mask;</div><div>+};</div><div>+</div><div>+/**</div><div>+ * struct rdt_resource - attributes of an RDT resource</div><div>+ * @enabled: Is this feature enabled on this machine</div><div>+ * @name: Name to use in "schemata" file</div><div>+ * @num_closid: Number of CLOSIDs available</div><div>+ * @max_cbm: Largest Cache Bit Mask allowed</div><div>+ * @min_cbm_bits: Minimum number of consecutive bits to be set</div><div>+ * in a cache bit mask</div><div>+ * @cache_level: Which cache level defines scope of this domain</div><div>+ * @num_banks: Number of cache bank on this machine.</div><div>+ * @cache_banks: Array of cache bank</div><div>+ */</div><div>+typedef struct _virResCtrl virResCtrl;</div><div>+typedef virResCtrl *virResCtrlPtr;</div><div>+struct _virResCtrl {</div><div>+ bool enabled;</div><div>+ const char *name;</div><div>+ int num_closid;</div><div>+ int cbm_len;</div><div>+ int min_cbm_bits;</div><div>+ const char* cache_level;</div><div>+ int num_banks;</div><div>+ virResCacheBankPtr cache_banks;</div><div>+};</div><div>+</div><div>+</div><div>+bool virResCtrlAvailable(void);</div><div>+int virResCtrlInit(void);</div><div>+virResCtrlPtr virResCtrlGet(int);</div><div>+</div><div>+#endif</div><div>--</div><div>1.9.1</div></div></blockquote></div></div></span>
</div></blockquote><div>
<br>
</div>