出色管理者如何帮助团队成员解决问题

这篇文章Don’t solve problems if you want to be a great manager 是出自medium 作者 Claire Lew 当一个团队管理者遇到团队成员来寻求帮助时,不应当自己立即介入,亲自帮助他们去解决问题,事实上那是在帮倒忙。 管理者的领导力就是可以使团队穿越千难万险,披荆斩棘,到达最终的目的地,并确保成员在旅途中有充分的补给和休息。 做为一个优秀的管理者应当是一名船长,而不是划船的人。 Leadership is stewardship , It’s navigating your team through trecherous waters, around jagged rocks, to the desired destination, and making sure folks feel nourished and rested along the way. 下面看看作者给出的建议,在与员工一对一的会议中, 从以下16个问题开始,而不必亲自解决问题: 你认为问题的根本原因是什么? 你正在考虑哪些可能的解决方案? 每种方案的优点和缺点是什么? 这种情况下你如何定义成功? 你如何知道自己会成功? 最坏的情况是什么? 最有可能的结果是什么? 问题场景中那一部分最不确定,最令人困惑、最难以预测? 你已经做了哪些尝试? 对于你最初选择某一解决方案是出于什么考虑? 还有没有其他的快速的解决方案? 在这个解决方案中有什么风险? 还有没有其他的解决方法? 如果什么都不做会怎样? 这是不是一个非此即彼的选择,你是不是漏掉了什么事情? 是不是有些事情你解释的太快了? 总之,一个出色的管理者应当更多关注团队的能力的培养 ,而不是自己。如果他们不能解决问题,可能是您选择了错误的人。

2020-08-12 · 1 min · 67 words

伙伴系统分配物理页后如何转换成为虚拟地址

概述 极客时间 26 | 内核态内存映射:如何找到正确的会议室? 一道课后问题 伙伴内存分配技术是一种内存分配算法,它将内存划分为多个分区,以尝试尽可能适当地满足内存请求。 该系统利用将内存分成两半来尝试提供最佳匹配。 当Linux内核态和用户态进程申请内存时, 分配的物理页面需要转化为虚拟地址供上层访问。 下面通过内核代码看下Linux内核态的kmalloc和vmalloc和用户态的mmap和malloc地址转换的时机。 内核态-kmalloc kmalloc 伙伴系统地址转换时机: __kmalloc申请空间小于2个页面大小时,申请发起后通过SLAB分配器进行分配, 依次检查 per cpu freelist per cpu partial per node partial链表是否有满足的的缓冲,没有就通过伙伴系统重新申请, 在申请的时候完成后page_address进行地址转换。 过程如下: 申请空间大于两个页面大小内存直接通过伙伴系统申请,小于这个值使用SLUB分配器(当然最终还是从伙伴系统申请内存) /include/linux/slab.h static __always_inline void *kmalloc(size_t size, gfp_t flags) { ... if (size > KMALLOC_MAX_CACHE_SIZE) return kmalloc_large(size, flags); ... return __kmalloc(size, flags); } ... #define KMALLOC_MAX_CACHE_SIZE (1UL << KMALLOC_SHIFT_HIGH) /* * SLUB directly allocates requests fitting in to an order-1 page * (PAGE_SIZE*2). Larger requests are passed to the page allocator. */ #define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1) 通过slab_alloc进入具体的内存申请流程. void *__kmalloc(size_t size, gfp_t flags) { struct kmem_cache *s; void *ret; if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) return kmalloc_large(size, flags); s = kmalloc_slab(size, flags); if (unlikely(ZERO_OR_NULL_PTR(s))) return s; ret = slab_alloc(s, flags, _RET_IP_); trace_kmalloc(_RET_IP_, ret, size, s->size, flags); ret = kasan_kmalloc(s, ret, size, flags); return ret; } 之后就从 <1> . per cpu freelist查找 static __always_inline void *slab_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node, unsigned long addr) { ... redo: ... do { tid = this_cpu_read(s->cpu_slab->tid); c = raw_cpu_ptr(s->cpu_slab); } while (IS_ENABLED(CONFIG_PREEMPTION) && unlikely(tid != READ_ONCE(c->tid))); ... object = c->freelist; page = c->page; ... if (unlikely(!object || !node_match(page, node))) { object = __slab_alloc(s, gfpflags, node, addr, c); stat(s, ALLOC_SLOWPATH); } else { ... } ... return object; } 然后从 <2> . per cpu partial查找 static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, unsigned long addr, struct kmem_cache_cpu *c) { ... new_slab: if (slub_percpu_partial(c)) { page = c->page = slub_percpu_partial(c); slub_set_percpu_partial(c, page); ... } ... } 然后从 <3> . per node partial查找 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags, int node, struct kmem_cache_cpu **pc) { void *freelist; struct kmem_cache_cpu *c = *pc; struct page *page; WARN_ON_ONCE(s->ctor && (flags & __GFP_ZERO)); freelist = get_partial(s, flags, node, c); ... } /* * Get a partial page, lock it and return it. */ static void *get_partial(struct kmem_cache *s, gfp_t flags, int node, struct kmem_cache_cpu *c) { void *object; int searchnode = node; if (node == NUMA_NO_NODE) searchnode = numa_mem_id(); object = get_partial_node(s, get_node(s, searchnode), c, flags); if (object || node != NUMA_NO_NODE) return object; return get_any_partial(s, flags, c); } 上面的经历了本地缓存池分配per cpu freelist,per cpu partial, 其他节点缓冲 per node partial, 逐一查找,但是一开始肯定要从伙伴系统分配的,下面看下伙伴系统分配,关注地址转换部分, 可以看到在申请slab时,通过page_address进行了物理地址到虚拟地址转换。 > 如果支持CONFIG_SLAB_FREELIST_RANDOM打乱了free_list中object顺序,减少堆栈溢出可预测性, 并有利于改善缓冲冲突 (Randomize free memory),对应 shuffle_freelist函数里也可看到相关地址映射的操作。 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags, int node, struct kmem_cache_cpu **pc) { ... page = new_slab(s, flags, node); if (page) { ... } return freelist; } static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) { ... return allocate_slab(s, flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node); } static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) { page = alloc_slab_page(s, alloc_gfp, node, oo); start = page_address(page); shuffle = shuffle_freelist(s, page); if (!shuffle) { ... page->freelist = start; ... } ... return page; } static bool shuffle_freelist(struct kmem_cache *s, struct page *page) { ... start = fixup_red_left(s, page_address(page)); ... cur = next_freelist_entry(s, page, &pos, start, page_limit, freelist_count); cur = setup_object(s, page, cur); page->freelist = cur; ... return true; } __kmalloc申请空间大于2个页面大小时,申请发起后, 直接就通过伙伴系统申请页了, 这里看到了熟悉的order ...

2020-08-11 · 12 min · 2346 words

文件时间信息

文件时间信息一般包含,文件创建时间,文件修改时间,文件访问时间。 Unix/Linux 文件修改时间有两个一个是(Modify Time 文件内容修改/ Change Time:文件权限状态/权限), 根据不同的文件系统,文件时间信息属性会有一些差别。Unix/Linux在挂载文件系统的时候会设置相关文件时间属性相关参数。 File Times in Linux 定义 Linux 早期内核版本也没有创建日期,在最新版本内核中已经可以看到相关字段 /include/linux/stat.h struct kstat { struct timespec64 atime; struct timespec64 mtime; struct timespec64 ctime; struct timespec64 btime; /* File creation time */ }; 不过glibc中没有相关接口 struct stat { /* These are the members that POSIX.1 requires. */ ... __time_t st_atime; /* Time of last access. */ __time_t st_mtime; /* Time of last modification. */ __time_t st_ctime; /* Time of last status change. */ ... }; 相关命令 ls ...

2020-07-30 · 3 min · 489 words

python修改excel文档相关日期信息

工作需要修改excel文件创建内容时间(excel属性非文件属性)和上次修改时间, 用python写了一个脚本处理了一下。 环境: windows10 python3.7 + openpyxl 1. 使用openpyxl修改excel属性 import openpyxl from datetime import datetime fh = openpyxl.load_workbook("results.xlsx") obj = fh.properties #To get old properties print( obj ) # print old properties fh.properties.created = datetime(2000,1,1, 8,30,11) fh.properties.modified = datetime(2000,2,1, 8,32,19) ##similarly you can set other fields ## new_obj = fh.properties #Now get new properties print ( new_obj ) # print new properties fh.save("results2.xlsx") 2.使用os.utime方法修改文件属性的访问时间,修改时间 import os, sys,time from datetime import datetime # Showing stat information of file stinfo = os.stat('results.xlsx') print (stinfo) # Using os.stat to recieve atime and mtime of file print ("access time of results.xlsx: %s" %stinfo.st_atime) print ("modified time of results.xlsx: %s" %stinfo.st_mtime) # Modifying atime and mtime t = datetime(2008, 1, 1, 12,12, 12) atime = time.mktime(t.timetuple()) t = datetime(2009, 1, 1, 12,12, 12) mtime = time.mktime(t.timetuple()) os.utime("results.xlsx",(atime, mtime)) print ("done!!") 3.使用pywin32-SetFileTime方法修改文件属性的创建日期, 访问时间,修改时间 from win32file import CreateFile, SetFileTime, GetFileTime, CloseHandle from win32file import GENERIC_READ, GENERIC_WRITE, OPEN_EXISTING from pywintypes import Time import time from datetime import datetime def modifyFileTime(filePath, createTime, modifyTime, accessTime): try: fh = CreateFile(filePath, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, 0) createTimes = Time(createTime) accessTimes = Time(modifyTime) modifyTimes = Time(accessTime) print (createTimes, accessTimes, modifyTimes) SetFileTime(fh, createTimes, accessTimes, modifyTimes) CloseHandle(fh) return 0 except: return 1 if __name__ == '__main__': t = datetime (2019, 12,13,21,51,2) cTime = time.mktime(t.timetuple()) t = datetime (2019, 2,2,0,1,3) mTime = time.mktime(t.timetuple()) t = datetime (2019, 2,2,0,1,4) aTime = time.mktime(t.timetuple()) fName = r"results.xlsx" r = modifyFileTime(fName, cTime, mTime, aTime) if r == 0: print('修改完成') elif r == 1: print('修改失败') 参考及引用 Openpyxl Doc python 修改文件的创建时间、修改时间、访问时间 pythondoc-os.utime In Python, how do you convert a datetime object to seconds? python ImportError: No module named win32file

2020-07-29 · 2 min · 270 words

LeetCode-Construct Binary Tree from Preorder and Inorder Traversal

题目: Given preorder and inorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. For example, given preorder = [3,9,20,15,7] inorder = [9,3,15,20,7] Return the following binary tree: 3 / \ 9 20 / \ 15 7 实现: 递归方式,根据二叉树中序遍历和前续遍历,创建二叉树。中序遍历: 左-根-右,前续遍历: 根-左-右, 所以可以通过前续遍历的第一个节点找到根节点,并生成根节点, 因为二叉树没有重复节点, 就 可以在中序遍历数据中找到根节点,再分成左右两个子树,递归执行下去,遍历完所有节点。 通过preorder获取根节点, 通过inorder生成左右子树,查找节点在中序遍历数据组里位置,java可以通过HashMap实现。 不使用map情况下 时间复杂度 O(N^2) , 使用map查找O(N) /** java * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */ class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { Map<Integer, Integer> treemap = new HashMap <>(); for (int i=0; i<inorder.length; i++){ treemap.put(inorder[i], i); } AtomicInteger rootindex = new AtomicInteger(0); return helper(preorder, inorder, 0, inorder.length -1, rootindex, treemap); } public TreeNode helper(int[] preorder, int[] inoder, int left, int right, AtomicInteger index, Map<Integer, Integer> treemap) { if (left > right){ return null; } //new node, set root int val = preorder[index.intValue()]; TreeNode node = new TreeNode(val); index //search inorder int root = treemap.get(val); //left substree node.left = helper(preorder, inoder, left, root-1, index, treemap); //right substree node.right = helper(preorder, inoder, root+1, right, index, treemap); return node ; } } 参考及引用: techiedelight-construct-binary-tree-from-inorder-preorder-traversal

2020-07-28 · 2 min · 231 words

LeetCode-Lowest Common Ancestor of a Binary Tree Solution

题目: Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).” Given the following binary tree: root = [3,5,1,6,2,0,8,null,null,7,4] ...

2020-07-28 · 2 min · 262 words

LeetCode – Construct Binary Tree from Inorder and Postorder Traversal

题目: Given inorder and postorder traversal of a tree, construct the binary tree. Note: You may assume that duplicates do not exist in the tree. For example, given inorder = [9,3,15,20,7] postorder = [9,15,7,20,3] Return the following binary tree: 3 / \ 9 20 / \ 15 7 实现: 递归方式,根据二叉树中序遍历和后续遍历,创建二叉树。中序遍历: 左-根-右, 后续遍历: 左-右-根, 所以可以通过后续遍历的最后一个节点找到根节点,并生成根节点, 因为二叉树没有重复节点, 就 可以在中序遍历数据中找到根节点,再分成左右两个子树,递归执行下去,遍历完所有节点。 通过postorder获取根节点, 通过inorder生成左右子树,查找节点在中序遍历数据组里位置,可以通过unordered_map实现。 不使用map情况下 时间复杂度 O(N^2) , 使用map查找O(N) /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { unordered_map <int, int> treemap; for (int i=0; i<inorder.size();i++) { treemap[inorder[i]] = i; } int index = inorder.size()-1; return helper(inorder, postorder, 0, inorder.size()-1, &index, treemap); } TreeNode *helper(vector<int> & inorder, vector<int>& postorder, int left, int right, int *index , unordered_map<int, int>&treemap){ //check if (left > right){ return NULL; } // create root node /* destory postorder vector int val = postorder.back(); TreeNode *node = new TreeNode(val); postorder.pop_back(); */ int val = postorder[*index]; TreeNode *node = new TreeNode(val); (*index)--; // search inorder by array /* int root = -1; for (int i=left ; i <=right; i ++){ if (val == inorder[i]){ root = i; break; } } if (root == -1){ return node; }*/ // search inorder by map int root = treemap[val]; // create left & right node node->right = helper(inorder, postorder, root+1, right, index, treemap); node->left = helper(inorder, postorder, left, root-1, index, treemap); return node; } };

2020-07-25 · 2 min · 272 words

Why mmap is faster than system calls

原文链接 作者 Alexandra (Sasha) Fedorova 关于mmap为什么比系统调用快,作者通过实验进行了验证,通过连续,随机,进行缓存, 不进行缓存,分为4种情况 文件连续访问且被缓存 文件连续访问且未被缓存 文件随机访问且被缓存 文件随机访问且未被缓存 实验结果发现出去少数例外, mmap比系统调用快2-6倍 通过专业的CPU检测工具可以看到 系统调用 60%左右时间 花费在copy_user_enhanced_fast_string 一个复制到用户空间的函数。 mmap 60%左右的时间花费在__memmove_avx_unaligned_erms和36%时间花在设置页面映射的各种操作上 可以看到两种方式用在复制的时间大概都在60%, mmap复制只用了AVX技术结合CPU预取功能,使mmap的确非常快。 AVX for wiki 是x86架构微处理器中的指令集,由英特尔在2008年3月提出,并在2011年 第一季度发布的Sandy Bridge系列处理器中首次支持[1]。AMD在随后的 2011年第三季度发布的Bulldozer系列处理器中开始支持AVX[2]。AVX指令 集提供了新的特性、指令和编码方案。 AVX是X86指令集的SSE延伸架构,如IA16至IA32般的把寄存器XMM 128bit 提升至YMM 256bit,以增加一倍的运算效率。此架构支持了三运算指令 (3-Operand Instructions),减少在编码上需要先复制才能运算的动 作。在微码部分使用了LES LDS这两少用的指令作为延伸指令Prefix。 为什么内核实现不能使用AVX 因为如果这样做了,那么它将必须在每个系统调用中保存和恢复那些寄存器,这将使内核态到用户态变得更加昂贵。 因此,这是Linux内核中的一个有意识的决定.

2020-07-24 · 1 min · 41 words

mmap相关API

概述 mmap()调用进程的虚拟进程空间中一段新的内存映射。 #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); mmap(2) — Linux manual page 用途 变更的可见性 映射类型 文件 匿名 私有 根据文件内容初始化内存 内存分配 共享 内存映射I/O,进程间共享内存(IPC) 进程间共享内存(IPC) 文件映射 创建步骤 //1. 打开使用的文件 fd = open(argv[1], O_RDONLY); //2.获取文件信息,文件大小 fstat(fd, &sb); //3. 生成内存映射 addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 相关议题 文件权限与内存保护位prot fd = open(argv[1], O_RDONLY); ... addr = mmap(NULL, sb.st_size, PROT_WRITE, MAP_SHARED, fd, 0); mmap抛出 errno=13 Permission denied错误 边界情况 增加一个异常捕获的处理 void signal_handler(int no){ switch(no){ case 11: printf("get SIGSEGV\n"); break; case 7: printf("get SIGBUS\n"); break; default: printf("get %d\n", no); break; } exit(-1); } # ls -l dax.file -rw-r--r--. 1 root root 7 Jul 18 17:51 dax.file SIGSEGV 访问超过mmap映射范围 ...

2020-07-22 · 4 min · 732 words

centos7 升级 glibc && gcc

环境 cenos7(X86_64) 为了验证 mmap()一些功能需要升级glibc版本, 顺便把gcc一起升级一下 升级gcc 预安装包 安装过程中需要makeinfo, 先安装下texi2html, texinfo yum install texi2html texinfo 安装gcc wget https://ftp.gnu.org/gnu/gcc/gcc-10.1.0/gcc-10.1.0.tar.gz tar zxvf gcc-10.1.0.tar.gz cd gcc-10.1.0/ mkdir build cd build /configure --enable-languages=c,c++ --disable-multilib make && make install 验证 # gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=... Target: x86_64-pc-linux-gnu Configured with: ../configure --enable-languages=c,c++ --disable-multilib Thread model: posix Supported LTO compression algorithms: zlib gcc version 10.1.0 (GCC) 升级glibc 预安装包 我的机器上是要求安装最新的make, 网上有需要升级ld, 的下载安装binutils就可以了 wget https://ftp.gnu.org/pub/gnu/make/make-4.3.tar.gz tar zxvf make-4.3.tar.gz cd make-4.3 mkdir build ./configure make && make install cp /usr/bin/make make.backup ln /usr/local/bin/make /usr/bin/make 安装glibc wget http://ftp.gnu.org/gnu/glibc/glibc-2.31.tar.gz tar -xvf glibc-2.31.tar.gz mkdir glibc-2.31/build cd glibc-2.31/build ../configure --prefix=/usr --with-headers=/usr/include --with-binutils=/usr/bin make make install 问题 make install 报错 /usr/bin/perl scripts/test-installation.pl /tmp/glibc-2.31/build/ /usr/bin/ld: cannot find -lnss_test2 ... LD_SO=ld-linux-x86-64.so.2 CC="gcc -B/usr/bin/" /usr/bin/perl scripts/test-installation.pl /tmp/glibc-2.31/build/ /usr/bin/ld: /lib/../lib64/libnss_nis.so: undefined reference to '_nsl_default_nss@GLIBC_PRIVATE' 可以从上面脚本信息看到是 scripts/test-installation.pl 有报错, 进去看一下, 主目录下的 Makefile ...

2020-07-18 · 3 min · 433 words