Go语言实践技巧(7)——value receiver和pointer receiver

Value receiver:

func (u user) fun1() {
    ....
}

Pointer receiver:

func (u *user) fun2() {
    ....
}

Value receiver操作的是值的拷贝,而pointer receiver操作的是实际的值。

pointer去调用value receiver的方法,实际的操作是:

(*p).fun1()

而用value去调用pointer receiver的方法,实际的操作是:

(&v).fun2()

参考资料:
Go in Action

Go语言实践技巧(6)——map key的选择

The map key can be a value from any built-in or struct type as long as the value can be used in an expression with the == operator. Slices, functions, and struct types that contain slices can’t be used as a map key.

 

map key可以使用任何内置类型或结构类型的值,只要这个值可以使用在==表达式中。slice,函数,和包含slice的结构体不能用作key

参考资料:
Go in Action

Shark代码分析笔记(3)——shark_init.lua

看一下shark_init.lua这个文件(省去版权信息):

local uv = require("uv")
local ffi = require("ffi")

package.path = package.path .. ";./deps/?.lua"
package.cpath = package.cpath .. ";./deps/?.so"

-- microsecond precision
ffi.cdef[[
typedef long time_t;

typedef struct timeval {
    time_t tv_sec;
    time_t tv_usec;
} timeval;

int gettimeofday(struct timeval *t, void *tzp);
]]

local gettimeofday_struct = ffi.new("timeval")

shark.gettimeofday = function()
  ffi.C.gettimeofday(gettimeofday_struct, nil)
  return tonumber(gettimeofday_struct.tv_sec) * 1000000 +
         tonumber(gettimeofday_struct.tv_usec)
end

set_interval = function(callback, interval)
  local timer = uv.new_timer()
  local function ontimeout()
    callback(timer)
  end
  uv.timer_start(timer, interval, interval, ontimeout)
  return timer
end

set_timeout = function(callback, timeout)
  local timer = uv.new_timer()
  local function ontimeout()
    uv.timer_stop(timer)
    uv.close(timer)
    callback(timer)
  end
  uv.timer_start(timer, timeout, 0, ontimeout)
  return timer
end

local shark_end_notify_list = {}

shark.add_end_notify = function(callback)
  table.insert(shark_end_notify_list, callback)
end

shark.on_end = function(callback)
  local function call_end()
    --notify registered on_end function
    for _, cb in pairs(shark_end_notify_list) do
      cb()
    end

    callback()
    os.exit(0)
  end
  local sigint = uv.new_signal()
  uv.signal_start(sigint, "sigint", function()
    call_end()
  end)

  local sigterm = uv.new_signal()
  uv.signal_start(sigterm, "sigterm", function()
    call_end()
  end)
end


---------------------------------------------------------------

local function fill_line(n, max)
  for i = 1, max do
    if i < n then
      io.write("*")
    else
      io.write(" ")
    end
  end
end

-- standard histogram print function
-- all type keys and number value
local __print_hist = function(t, cmp_func, mode)
  local stdSum = 0
  local array = {}

  for k, v in pairs(t) do
    stdSum = stdSum + v
    if tostring(k) ~= "" then
      array[#array + 1] = {k = k, v = v}
    end
  end

  table.sort(array, function(v1, v2)
    if cmp_func ~= nil then
      return cmp_func(v1.v, v2.v)
    else
      if v1.v > v2.v then return true end
    end
  end)

  if mode == "default" then
    io.write("                          value  ---------- Distribution ----------  count\n")
  end

  for k, v in pairs(array) do
    if mode == "default" then
      io.write(string.format("%33s |", tostring(v.k)))
      fill_line(v.v * 34 / stdSum, 34)
      io.write(string.format("| %d\n", v.v))
    else
      io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
    end
  end
end

function print_hist(t, cmp_func)
  __print_hist(t, cmp_func, "default")
end


function print_hist_raw(t, cmp_func)
  __print_hist(t, cmp_func, "raw")
end

shark.print_hist = print_hist
shark.print_hist_raw = print_hist_raw

(1)

local uv = require("uv")
local ffi = require("ffi")

package.path = package.path .. ";./deps/?.lua"
package.cpath = package.cpath .. ";./deps/?.so"

require("uv")加载luv模块(在main函数中已经将luaopen_luv注册进了package.preload table),require("ffi")加载luajit中的ffi模块。
然后修改package.pathpackage.cpath,这样可以找到shark依赖的lua文件和库。

(2)

-- microsecond precision
ffi.cdef[[
typedef long time_t;

typedef struct timeval {
    time_t tv_sec;
    time_t tv_usec;
} timeval;

int gettimeofday(struct timeval *t, void *tzp);
]]

local gettimeofday_struct = ffi.new("timeval")

shark.gettimeofday = function()
  ffi.C.gettimeofday(gettimeofday_struct, nil)
  return tonumber(gettimeofday_struct.tv_sec) * 1000000 +
         tonumber(gettimeofday_struct.tv_usec)
end

ffi.new()返回一个cdata类型的值。shark.gettimeofday返回的是当前时间的微秒(us)值。

(3)

set_interval = function(callback, interval)
  local timer = uv.new_timer()
  local function ontimeout()
    callback(timer)
  end
  uv.timer_start(timer, interval, interval, ontimeout)
  return timer
end

set_timeout = function(callback, timeout)
  local timer = uv.new_timer()
  local function ontimeout()
    uv.timer_stop(timer)
    uv.close(timer)
    callback(timer)
  end
  uv.timer_start(timer, timeout, 0, ontimeout)
  return timer
end

set_intervalset_timeout利用了luv模块中定时器相关函数。set_interval函数会让callback函数间隔interval时间执行。而set_timeout函数会让callback函数在timeout后执行,且执行一次。要注意这两个函数的时间单位是毫秒(ms)。

(4)

local shark_end_notify_list = {}

shark.add_end_notify = function(callback)
  table.insert(shark_end_notify_list, callback)
end

创建一个shark_end_notify_listtable,并且定义一个shark.add_end_notify的函数。这个函数的作用是向shark_end_notify_list添加回调函数(callback),这个table中的函数会在shark.on_end这个函数中调用,也就是在脚本退出时执行收尾工作。

(5)

shark.on_end = function(callback)
  local function call_end()
    --notify registered on_end function
    for _, cb in pairs(shark_end_notify_list) do
      cb()
    end

    callback()
    os.exit(0)
  end
  local sigint = uv.new_signal()
  uv.signal_start(sigint, "sigint", function()
    call_end()
  end)

  local sigterm = uv.new_signal()
  uv.signal_start(sigterm, "sigterm", function()
    call_end()
  end)
end

shark.on_end函数的参数是一个回调函数(callback)。在shark.on_end里定义了一个local函数:call_endcall_end首先会遍历shark_end_notify_list,并把其中的函数都执行一遍,最后调用shark.on_end函数传入的回调函数(callback)。 call_end函数就是shark.on_end函数为sigintsigterm信号注册的信号处理函数。

(6)

local function fill_line(n, max)
  for i = 1, max do
    if i < n then
      io.write("*")
    else
      io.write(" ")
    end
  end
end

fill_line函数用来输出*,用在接下来的__print_hist函数中。

(7)

-- standard histogram print function
-- all type keys and number value
local __print_hist = function(t, cmp_func, mode)
  local stdSum = 0
  local array = {}

  for k, v in pairs(t) do
    stdSum = stdSum + v
    if tostring(k) ~= "" then
      array[#array + 1] = {k = k, v = v}
    end
  end

  table.sort(array, function(v1, v2)
    if cmp_func ~= nil then
      return cmp_func(v1.v, v2.v)
    else
      if v1.v > v2.v then return true end
    end
  end)

  if mode == "default" then
    io.write("                          value  ---------- Distribution ----------  count\n")
  end

  for k, v in pairs(array) do
    if mode == "default" then
      io.write(string.format("%33s |", tostring(v.k)))
      fill_line(v.v * 34 / stdSum, 34)
      io.write(string.format("| %d\n", v.v))
    else
      io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
    end
  end
end

__print_hist函数用来打印柱状图。

  local stdSum = 0
  local array = {}

  for k, v in pairs(t) do
    stdSum = stdSum + v
    if tostring(k) ~= "" then
      array[#array + 1] = {k = k, v = v}
    end
  end

输入参数t是一个table。以上代码是遍历这个table,并且生成一个新的“array table”。这个array的值又是一个table:包含输入tablekeyvalue

table.sort(array, function(v1, v2)
    if cmp_func ~= nil then
      return cmp_func(v1.v, v2.v)
    else
      if v1.v > v2.v then return true end
    end
  end)

以上代码是对array进行排序。如果没有输入cmp_func函数参数,就用默认的比较方式。

if mode == "default" then
    io.write("                          value  ---------- Distribution ----------  count\n")
  end

  for k, v in pairs(array) do
    if mode == "default" then
      io.write(string.format("%33s |", tostring(v.k)))
      fill_line(v.v * 34 / stdSum, 34)
      io.write(string.format("| %d\n", v.v))
    else
      io.write(string.format("%s\n%d\n", tostring(v.k), v.v))
    end
  end

以上代码就是打印最后的柱状图了。输出结果类似:

                           value  ---------- Distribution ----------  count
  syscalls:sys_enter_gettimeofday |********                          | 25940
   syscalls:sys_exit_gettimeofday |********                          | 25940
    syscalls:sys_enter_epoll_wait |****                              | 12977
     syscalls:sys_exit_epoll_wait |****                              | 12977
          syscalls:sys_exit_alarm |*                                 | 3917

 

(8)

function print_hist(t, cmp_func)
  __print_hist(t, cmp_func, "default")
end


function print_hist_raw(t, cmp_func)
  __print_hist(t, cmp_func, "raw")
end

shark.print_hist = print_hist
shark.print_hist_raw = print_hist_raw

最后就是把__print_hist封装出shark.print_histshark.print_hist_raw两个函数供其它程序调用。

 

 

 

 

git remote 命令简介

git remote会列出所有的remote repository名字,详细信息可以通过git remote -v得到。

git remote add <remote-name> <remote-path>可以添加一个remote repository,并且指定名字为<remote-name>。举例如下:

git remote add mary ../marys-repo

git fetch <remote-name>则是下载remote repository,但是不会merge

git merge <remote-name>/<branch-name>则是把<remote-name>/<branch-name>所指定的branch merge到当前的branch。举例如下:

git merge mary/master

git push <remote-name> <branch-name>是把本地一个branch上传到<remote-name>所指定的remote repository。举例如下:

git push mary dummy

git push <remote-name> <tag-name>则是上传指定的tag

git branch -r列出所有remote branch

Linux kernel IOMMU代码分析笔记(9)——EIM,IR和QI

支持IOMMU的硬件单元的Extended Capability Register有三个关联的位:

EIMExtended Interrupt Mode):在X86_64平台,0表示支持xAPIC1表示支持x2APICItanium平台这一位没意义。并且这一位只有在IR位设置为1才有效。

IRInterrupt Remapping support):1表示支持Interrupt remapping0表示不支持。硬件单元支持Interrupt remapping,也必须支持QI

QIQueued Invalidation support):1支持Queued Invalidation0表示不支持。

参考资料:
Intel ® Virtualization Technology for Directed I/O

Linux kernel IOMMU代码分析笔记(8)——intel_enable_irq_remapping(2)

上文

(4)

for_each_iommu(iommu, drhd) {
    /*
     * If the queued invalidation is already initialized,
     * shouldn't disable it.
     */
    if (iommu->qi)
        continue;

    /*
     * Clear previous faults.
     */
    dmar_fault(-1, iommu);

    /*
     * Disable intr remapping and queued invalidation, if already
     * enabled prior to OS handover.
     */
    iommu_disable_irq_remapping(iommu);

    dmar_disable_qi(iommu);
}

上面代码含义是如果硬件单元的queued invalidation还没有初始化,则清掉之前的fault,并且disable IRQ remappingqueued invalidation

(5)

/*
 * check for the Interrupt-remapping support
 */
for_each_iommu(iommu, drhd) {
    if (!ecap_ir_support(iommu->ecap))
        continue;

    if (eim && !ecap_eim_support(iommu->ecap)) {
        printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
               " ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
        goto error;
    }
}

上述代码含义是如果硬件支持IRQ remapping并且系统支持x2APIC模式,如果硬件不支持x2APIC模式,就失败。

(6)

/*
 * Enable queued invalidation for all the DRHD's.
 */
for_each_iommu(iommu, drhd) {
    int ret = dmar_enable_qi(iommu);

    if (ret) {
        printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
               " invalidation, ecap %Lx, ret %d\n",
               drhd->reg_base_addr, iommu->ecap, ret);
        goto error;
    }
}

/*
 * Setup Interrupt-remapping for all the DRHD's now.
 */
for_each_iommu(iommu, drhd) {
    if (!ecap_ir_support(iommu->ecap))
        continue;

    if (intel_setup_irq_remapping(iommu, eim))
        goto error;

    setup = 1;
}

if (!setup)
    goto error;

上述代码分别为每个硬件单元enable queued invalidationIRQ remapping

(7)

irq_remapping_enabled = 1;

/*
 * VT-d has a different layout for IO-APIC entries when
 * interrupt remapping is enabled. So it needs a special routine
 * to print IO-APIC entries for debugging purposes too.
 */
x86_io_apic_ops.print_entries = intel_ir_io_apic_print_entries;

pr_info("Enabled IRQ remapping in %s mode\n", eim ? "x2apic" : "xapic");

return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;

error:
    /*
     * handle error condition gracefully here!
     */

if (x2apic_present)
    pr_warn("Failed to enable irq remapping.  You are vulnerable to irq-injection attacks.\n");

return -1;

如果成功的话,返回IRQ_REMAP_XAPIC_MODE(0)IRQ_REMAP_X2APIC_MODE(1),否则返回-1

参考资料:
"BIOS Considerations" in *Intel ® Virtualization Technology for Directed I/O

git reset简介

git reset把当前branchHEAD恢复到之前某个snapshot。举例如下:

假设当前repository分三次添加abc文件:

[root@localhost test_git]# git log --oneline
e5b4692 Add c
be89e2d Add b
80c615e Add a

执行git reset --hard HEAD~1命令,HEAD~1表示当前HEAD之前的第一个commit

[root@localhost test_git]# git reset --hard HEAD~1
HEAD is now at be89e2d Add b
[root@localhost test_git]# git status
On branch master
nothing to commit, working directory clean
[root@localhost test_git]# git log --oneline
be89e2d Add b
80c615e Add a
[root@localhost test_git]# ls
a  b

可以看到git log中已经找不到添加c文件的log。而c文件也不存在了。

如果执行git reset --mixed HEAD~1命令,则虽然repository已经回滚到HEAD之前的第一个commit,但c文件还会存在:

[root@localhost test_git]# git reset --mixed HEAD~1
[root@localhost test_git]# git log --oneline
be89e2d Add b
80c615e Add a
[root@localhost test_git]# ls
a  b  c

恢复之前HEAD状态,可以利用git reflog找到相应的commit,然后创建一个新的branch,最后mergemaster:

[root@localhost test_git]# git reflog
be89e2d HEAD@{0}: reset: moving to HEAD~1
deb862b HEAD@{1}: commit: Add c
be89e2d HEAD@{2}: reset: moving to HEAD~1
e5b4692 HEAD@{3}: commit: Add c
be89e2d HEAD@{4}: commit: Add b
80c615e HEAD@{5}: commit (initial): Add a
[root@localhost test_git]# git checkout deb862b
Note: checking out 'deb862b'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at deb862b... Add c
[root@localhost test_git]# git log --oneline
deb862b Add c
be89e2d Add b
80c615e Add a
[root@localhost test_git]# git branch
* (HEAD detached at deb862b)
  master
[root@localhost test_git]# git checkout -b temp
Switched to a new branch 'temp'
[root@localhost test_git]# git branch
  master
* temp
[root@localhost test_git]# git checkout master
Switched to branch 'master'
[root@localhost test_git]# git merge temp
Updating be89e2d..deb862b
Fast-forward
 c | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 c
 [root@localhost test_git]# ls
a  b  c