oneflow icon indicating copy to clipboard operation
oneflow copied to clipboard

Cached attr map

Open lixinqi opened this issue 3 years ago • 6 comments

将Functor::operator()内的创建AttrMap的过程缓存起来,从3-7us开销优化到300-500ns。这个300-50ns还是在nsys上的测量值,实际时间估计在100ns一下。

lixinqi avatar Jul 20 '22 11:07 lixinqi

我在想能不能通过修改AttrMap的数据结构来达到类似的目的,比如每个接口中都存在一个thread_local static的CachedAttrMap,每次执行到这个接口的时候CachedAttrMap都会先fake clear一下,fake clear只是把里面存有的元素都标记为invalid,后面在SetAttr的时候会判断val和invalid的val是不是相同,相同的话就把它重新标记为valid,否则就更新val的值。这样的实现相比于缓存整个AttrMap来说,代码改动会小一些,效果会在缓存大小为1到n之间(n为属性个数),因为每次可能都只需要更新少量的几个属性。

hjchen2 avatar Jul 26 '22 02:07 hjchen2

我在想能不能通过修改AttrMap的数据结构来达到类似的目的,比如每个接口中都存在一个thread_local static的CachedAttrMap,每次执行到这个接口的时候CachedAttrMap都会先fake clear一下,fake clear只是把里面存有的元素都标记为invalid,后面在SetAttr的时候会判断val和invalid的val是不是相同,相同的话就把它重新标记为valid,否则就更新val的值。这样的实现相比于缓存整个AttrMap来说,代码改动会小一些,效果会在缓存大小为1到n之间(n为属性个数),因为每次可能都只需要更新少量的几个属性。

我感觉成本还是不低,比如SetAttr<T>("foo", bar)。这代码内部就涉及到不少对象创建,首先"foo"需要转成std::string,还有对map的查找。

lixinqi avatar Aug 03 '22 05:08 lixinqi

我感觉成本还是不低,比如SetAttr("foo", bar)。这代码内部就涉及到不少对象创建,首先"foo"需要转成std::string,还有对map的查找。

但这个可能并不是瓶颈,主要是会节约创建AttrMap和插入的开销,而且对代码改动很小。

hjchen2 avatar Aug 03 '22 05:08 hjchen2

我感觉成本还是不低,比如SetAttr("foo", bar)。这代码内部就涉及到不少对象创建,首先"foo"需要转成std::string,还有对map的查找。

但这个可能并不是瓶颈,主要是会节约创建AttrMap和插入的开销,而且对代码改动很小。

目前整个attr_map 缓存起来有效的根本原因是用创建std::tuple的成本代替了std::map。如果那里不是瓶颈,也许会比当前方案效果更好。

lixinqi avatar Aug 03 '22 05:08 lixinqi

我在想能不能通过修改AttrMap的数据结构来达到类似的目的,比如每个接口中都存在一个thread_local static的CachedAttrMap,每次执行到这个接口的时候CachedAttrMap都会先fake clear一下,fake clear只是把里面存有的元素都标记为invalid,后面在SetAttr的时候会判断val和invalid的val是不是相同,相同的话就把它重新标记为valid,否则就更新val的值。这样的实现相比于缓存整个AttrMap来说,代码改动会小一些,效果会在缓存大小为1到n之间(n为属性个数),因为每次可能都只需要更新少量的几个属性。

我还对这个方案有另一个顾虑。attr_map会在多个线程里传递,最好是只读的,这和只cache某个字段有点冲突。

lixinqi avatar Aug 03 '22 05:08 lixinqi

我在想能不能通过修改AttrMap的数据结构来达到类似的目的,比如每个接口中都存在一个thread_local static的CachedAttrMap,每次执行到这个接口的时候CachedAttrMap都会先fake clear一下,fake clear只是把里面存有的元素都标记为invalid,后面在SetAttr的时候会判断val和invalid的val是不是相同,相同的话就把它重新标记为valid,否则就更新val的值。这样的实现相比于缓存整个AttrMap来说,代码改动会小一些,效果会在缓存大小为1到n之间(n为属性个数),因为每次可能都只需要更新少量的几个属性。

我还对这个方案有另一个顾虑。attr_map会在多个线程里传递,最好是只读的,这和cache有点冲突。

其实也不会,CachedAttrMap会拷贝一份转成AttrMap,因为内部元素是shared_ptr<AttrVal>,如果在main线程里又更新了CachedAttrMap,那也是把它的元素替换成了另一个shared_ptr<AttrVal>,并不影响其他线程里的元素。

hjchen2 avatar Aug 03 '22 05:08 hjchen2

后江的这个pr改动更加平滑。https://github.com/Oneflow-Inc/oneflow/pull/8943

lixinqi avatar Sep 06 '22 03:09 lixinqi