<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Nov 18, 2014 at 9:57 PM, wuhui1973 <span dir="ltr"><<a href="mailto:wuhui1973@163.com" target="_blank">wuhui1973@163.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial">Hello David:</div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><br></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial">Do you have any comment?</div></div></div></blockquote><div><br>Did you see my email (on this thread) from yesterday where I mentioned my commits r<span style="font-family:monospace">222183, r221926? I discuss some context there & I'm not sure you've read them/have that context.</span><br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><br></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial">Regards</div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial">Hui Wu</div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><br></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span class=""><br>At 2014-11-12 10:22:22, "David Blaikie" <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br> </span><blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><span class=""><div dir="ltr">OK, so you're saying all the heap allocated TreePatterns and TreePatternNodes are currently leaked? And we create some on the stack (that obviously don't leak)?</div><div dir="ltr"><br></div></span><div dir="ltr"><span class=""> >> [huiwu] Yes, almost all. And quite a few TreePatterns are created on stack, which will not leak.<br><br></span><span class="">And from previous discussions we've seen that TreePatterns and TreePatternNodes form unbreakable(?) cycles. (are they unbreakable - could we use weak_ptr or raw pointer in there somewhere to break them safely? I'll have to go back & look at the prior threads or you could copy/paste the summary of the cycles you saw? - though the only reason this would be worth understanding is if we actually destroy things at some point other than the end - I don't know anything about tablegen or when nodes are created and destroyed, I'm not sure if they're destroyed at any time other than "we've finished doing all the work, cleanup now")</span></div><div dir="ltr"><br></div><span class=""><div dir="ltr">>> [huiwu] </div><div dir="ltr"><span style="line-height:23.7999992370605px">>> TreePatternNode has field </span><span style="line-height:23.7999992370605px">PredicateFns</span><span style="line-height:23.7999992370605px"> , which contains </span><span style="line-height:23.7999992370605px">PatFragRec, the pointer of </span><span style="line-height:23.7999992370605px">TreePattern</span></div><div dir="ltr"><span style="line-height:23.7999992370605px"><br></span></div></span><span style="line-height:23.7999992370605px">>> </span><span style="line-height:23.7999992370605px">TreePattern has Trees which is </span><span style="line-height:23.7999992370605px">std::vector<TreePatternNode*></span></blockquote><blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><br></blockquote><blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><span class=""><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span>The cycles exist among <span style="line-height:23.7999992370605px">PatFragRec & </span><span style="line-height:23.7999992370605px">Trees. May like this:</span><br><div dir="ltr"><span style="line-height:23.7999992370605px"><br></span></div></span><div dir="ltr"><span class=""><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span>TreePatternNode <---------------------------------------------------------------+</div><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span> PredicateFns (std::vector<TreePredicateFn>) |</div><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span> PatFragRec ------> TreePattern |</div></span><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span> ^ Trees (std::vector<TreePatternNode*>) +------------> Other TreePatternNode</div><span class=""><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span> |</div><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:1.7">Other TreePatternNode |</span></div><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:1.7"> </span><span style="line-height:23.7999992370605px">PredicateFns</span><span style="line-height:23.7999992370605px"> |</span></div><div style="line-height:23.7999992370605px"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:1.7"> </span><span style="line-height:23.7999992370605px">PatFragRec</span><span style="line-height:23.7999992370605px"> -----+</span></div></span></div></blockquote></div></div></div></blockquote><div><br>So the thing that's still unclear to me from this diagram is just where the /ownership/ happens (or needs to happen, as we add it). <br><br>Do all the references to a TreePattern via PredicateFns/PatFragRecs come from TreePatternNodes that are in that TreePattern?<br><br>Do TreePatterns ever need to be kept alive via the PredicateFns/PatFragRecs, or are TreePatterns themselves always appropriately kept alive by the CodeGenDAGPatterns? If they are kept alive that way, then we don't need to deal with cycles in the ownership graph - we just break it at PatFragRec, leaving PatFragRec unowning (raw pointer, not a smart pointer) and having CodeGenDAGPatterns::Trees -> <span style="font-family:monospace">TreePattern::Trees -> TreePatternNode::Children (with children having more children, and so on). Which should all be unique_ptrs, since it's a tree.</span><br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div dir="ltr"><span class=""><div dir="ltr"><br></div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span>In previous solution, every TreePatternNode & TreePattern hold the reference count of objects pointed by <span style="line-height:23.7999992370605px">PatFragRec & </span><span style="line-height:23.7999992370605px">Trees. If they find the reference count reaches 0, </span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:23.7999992370605px">the associated</span><span style="line-height:23.7999992370605px"> </span><span style="line-height:23.7999992370605px">object will be freed. </span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>> At the end of the processing, I found around 700 TreePatternNodes & 100 TreePatterns (I forget the exact number) remains. Obviously, they form cycles which can't be</span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>> broken by reference count.</span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>> That is why we need </span>FreeCycleRef, in which <span style="line-height:23.7999992370605px">we can't explicit delete those objects, but just assign NULL to </span><span style="line-height:23.7999992370605px">PatFragRec & </span><span style="line-height:23.7999992370605px">Trees, their owner will do the rest for us.</span></div><div dir="ltr"><span style="line-height:23.7999992370605px"><br></span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:23.7999992370605px">But in current design, all heap allocated TreePatternNode & TreePattern will be recorded, and there is the mechanism (the operator delete) to remove the record if the object is </span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>> freed manually somewhere in the source. Then at the end of the process (the dtor of </span>CodeGenDAGPatterns), these records are all leaked objects. We just go through both </div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span>containers to free them. </div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:1.7">So as a requirement, </span><span style="line-height:23.7999992370605px">TreePatternNode's dtor is not allowed to delete pointers within </span><span style="line-height:23.7999992370605px">PatFragRec & Children (</span><span style="line-height:1.7">std::vector<TreePatternNode*>), and </span></div><div dir="ltr"><span style="line-height:23.7999992370605px">>></span><span style="line-height:23.7999992370605px"> </span><span style="line-height:23.7999992370605px">TreePattern's dtor is not allowed to delete pointers within Trees. All these objects are assumed to be deleted by MemReclaimer::reclaim.</span></div><div dir="ltr"><span style="line-height:23.7999992370605px"><br></span></div><br></span><div><div class="h5">If that's all the case, then it seems obvious enough that we should just have a big list of all the heap allocated ones, that goes away when we're done.<br></div></div></div><div><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Nov 11, 2014 at 6:07 PM, wuhui1973 <span dir="ltr"><<a href="mailto:wuhui1973@163.com" target="_blank">wuhui1973@163.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div>Sorry David:</div><div><br></div><div>I make a mistake in yesterday explanation.</div><div><br></div><div>Here is some data I collect during building Tablegen, the data is from x86 target</div><div><br></div><div>llvm[3]: Building X86.td instruction information with tblgen</div><div><span style="line-height:1.7">NumTPNAllocCur: 120754, NumTPNAllocAccu: 121469 <-- it indicates only 121469-120754=715 heap alloc TreePatternNodes get freed during processing (~0.5%)</span></div><div>NumTPAllocCur: 9488, NumTPAllocAccu: 9488 <-- in fact <b>NO</b> heap alloc TreePatterns get freed during processing</div><div>NumTPNAllocCur: 0, NumTPNDel: 121469</div><div>NumTPAllocCur: 0, NumTPDel: 9488</div><div>TPN dtorNum: 121469, TP dtorNum: 16821 <-- the diff "<span style="line-height:23.7999992370605px">NumTPAllocAccu"</span><span style="line-height:23.7999992370605px">-"</span><span style="line-height:23.7999992370605px">TPN dtorNum"</span><span style="line-height:23.7999992370605px">=0 indicates that all TreePatternNodes are heap allocated</span></div><div>TPN ctorNum: 121469, TP ctorNum: 16821 <-- the diff "<span style="line-height:23.7999992370605px">TP ctorNum"</span><span style="line-height:23.7999992370605px">-"</span><span style="line-height:23.7999992370605px">NumTPDel"</span><span style="line-height:23.7999992370605px">=7333 indicates that 7333 TreePatterns are placed into stack!</span></div><div><br></div><div><div>llvm[3]: Building X86.td DAG instruction selector implementation with tblgen</div><div>NumTPNAllocCur: 180382, NumTPNAllocAccu: 197494 <-- 17112 TreePatternNodes (~8%) get freed</div><div>NumTPAllocCur: 9488, NumTPAllocAccu: 9488<span style="line-height:23.7999992370605px"> <-- </span><b style="line-height:23.7999992370605px">NO</b><span style="line-height:23.7999992370605px"> heap alloc TreePatterns get freed during processing</span></div><div>NumTPNAllocCur: 0, NumTPNDel: 197494 <-- "<span style="line-height:23.7999992370605px">NumTPNDel" == "</span><span style="line-height:23.7999992370605px">TPN ctorNum": all TreePatternNodes all heap allocated</span></div><div>NumTPAllocCur: 0, NumTPDel: 9488</div><div>TPN dtorNum: 197494, TP dtorNum: 16821 <-- the diff <span style="line-height:23.7999992370605px">16821-</span><span style="line-height:23.7999992370605px">9488=</span><span style="line-height:23.7999992370605px">7333 indicates that 7333 TreePatterns are placed into stack!</span></div><div>TPN ctorNum: 197494, TP ctorNum: 16821</div></div><div><br></div><div>So more than 43% TreePatterns are stack residue for both processing.</div><div><br></div><div>And other target also gives similar data, for instance AMDGPU</div><div><br></div><div><div>llvm[3]: Building AMDGPU.td instruction information with tblgen</div><div>NumTPNAllocCur: 28248, NumTPNAllocAccu: 28348 <-- 100 TreePatternNodes (~0.3%) get freed</div><div>NumTPAllocCur: 2422, NumTPAllocAccu: 2422<span style="line-height:23.7999992370605px"> <-- </span><b style="line-height:23.7999992370605px">NO</b><span style="line-height:23.7999992370605px"> heap alloc TreePatterns get freed during processing</span></div><div>NumTPNAllocCur: 0, NumTPNDel: 28348</div><div>NumTPAllocCur: 0, NumTPDel: 2422</div><div>TPN dtorNum: 28348, TP dtorNum: 3792</div><div>TPN ctorNum: 28348, TP ctorNum: 3792 <-- 1370 TreePatterns are inside stack (>36%)</div><div>llvm[3]: Building AMDGPU.td DAG instruction selector implementation with tblgen</div><div>NumTPNAllocCur: 44076, NumTPNAllocAccu: 47030 <-- 2954 TreePatternNodes (~6%) get freed</div><div>NumTPAllocCur: 2422, NumTPAllocAccu: 2422<span style="line-height:23.7999992370605px"> <-- </span><b style="line-height:23.7999992370605px">NO</b><span style="line-height:23.7999992370605px"> heap alloc TreePatterns get freed during processing</span></div><div>NumTPNAllocCur: 0, NumTPNDel: 47030</div><div>NumTPAllocCur: 0, NumTPDel: 2422</div><div>TPN dtorNum: 47030, TP dtorNum: 3792</div><div>TPN ctorNum: 47030, TP ctorNum: 3792 <-- 1370 <span style="line-height:23.7999992370605px">TreePatterns are inside stack (>36%)</span></div></div><div><br></div><div><span style="line-height:1.7">There are several functions in CodeGenDAGPatterns.cpp will allocate TreePatternNodes & TreePatterns from heap.</span></div><div>ParsePatternFragments (5 spots allocate TreePatternNodes)</div><div>ParsePatterns (2 spots allocate TreePatternNodes, 2 spots allocate TreePatterns)</div><div>CombineChildVariants (1 spot allocate TreePatternNodes)</div><div>clone<span style="line-height:23.7999992370605px"> </span><span style="line-height:23.7999992370605px">(2 spots allocate TreePatternNodes)</span></div><div><span style="line-height:23.7999992370605px"><br></span></div><div>So I don't think there is any special construction path.</div><div><br></div><div>Regards</div><div>Hui Wu</div><div></div><div></div><br>在 2014-11-12 06:33:37,"David Blaikie" <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> 写道:<div><div><br> <blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 10, 2014 at 11:36 PM, wuhui1973 <span dir="ltr"><<a href="mailto:wuhui1973@163.com" target="_blank">wuhui1973@163.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div>Hope I can explain it clear enough :-)</div><div><br></div><div>> MemReclaimer has two containers to hold pointers of TreePatternNode & TreePattern which are allocated from heap.</div><div>> Only one global instance of <span style="line-height:23.7999992370605px">MemReclaimer</span><span style="line-height:23.7999992370605px"> is declared -- memReclaimer.</span></div><div><span style="line-height:23.7999992370605px">> operator new & operator delete are defined for </span><span style="line-height:23.7999992370605px">TreePatternNode & TreePattern </span></div><div><span style="line-height:23.7999992370605px"> new: push the new allocated object (pointer) into containers in </span><span style="line-height:23.7999992370605px">memReclaimer.</span></div><div><span style="line-height:23.7999992370605px"> delete: remove the pointer from the containers in </span><span style="line-height:23.7999992370605px">memReclaimer.</span></div><div><span style="line-height:23.7999992370605px"><br></span></div><div><span style="line-height:23.7999992370605px"> So we can </span>guarantee that objects allocated from heap can always be recorded by <span style="line-height:23.7999992370605px">memReclaimer.</span><span style="line-height:23.7999992370605px"> </span></div><div><span style="line-height:23.7999992370605px"> And no double free may incur, as some places in the source delete some pointers manually (maybe we can remove these lines</span><span style="line-height:23.7999992370605px">).</span></div><div><span style="line-height:23.7999992370605px">> So memReclaimer only keeps the objects that are leaked in current design.</span></div><div><span style="line-height:23.7999992370605px">> the author of </span><span style="line-height:23.7999992370605px">CodeGenDAGPattern </span><span style="line-height:23.7999992370605px"> create nodes, but destroy part of them (for TreePattern, the nodes </span><span style="line-height:1.7">destroyed</span><span style="line-height:23.7999992370605px"> manually account for more than 30%, </span></div></div></blockquote><div><br></div><div>Could you provide stack traces/explanation for these case where the TreePatterns are destroyed?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div><span style="line-height:23.7999992370605px"> for some target even over 50%; while for TreePatternNode only around 1%</span></div></div></blockquote><div><br>And for the TreePatternNodes?<br><br>If they're mostly just on special case construction paths, perhaps we could special case their removal from the list we could add to CodeGenDAGPattern - or, if they're close enough to construction time, we might be able to avoid adding them to such a list in the first place?<br> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div><span style="line-height:23.7999992370605px">) and make the rest leaked deliberately.</span></div><div>> dtor of <span style="line-height:23.7999992370605px">CodeGenDAGPattern now is the place to </span>destroy<span style="line-height:23.7999992370605px"> all not freed objects</span></div><div><span style="line-height:23.7999992370605px">> move the functionality of </span><span style="line-height:23.7999992370605px">MemReclaimer</span><span style="line-height:23.7999992370605px"> into </span><span style="line-height:23.7999992370605px">CodeGenDAGPattern </span><span style="line-height:23.7999992370605px"> is definitely feasible I think.</span><span style="font-family:arial;font-size:small;line-height:normal;color:rgb(34,34,34)"> </span></div></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div><br></div><div>Regards</div><div>Hui Wu</div><div><div><div><br></div><div></div><div></div><br>At 2014-11-11 14:20:25, "David Blaikie" <<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>> wrote:<br> <blockquote style="padding-left:1ex;margin:0px 0px 0px 0.8ex;border-left-color:rgb(204,204,204);border-left-width:1px;border-left-style:solid"><div dir="ltr">Could you describe the high level design here?<br><br>It looks like there's a static pool (CodeGenDAGPatterns.cpp::memReclaimer) of instances that's used as some kind of last-chance cleanup? Instances of TreePatternNode mostly manage their own lifetime but then if any haven't been destroyed by the time the CodeGenDAGPatterns dtor runs, the remaining elements are destroyed. This is to handle cycles, I take it?<br><br>It still seems like a bit of a GC-esque workaround to handle this case when there might be something better... but I don't know much about tablegen, perhaps there isn't.<br><br>How often are nodes destroyed by themselves? Should we just give up owning these anywhere else & move all ownership into CodeGenDAGPatterns and clean them up in CodeGenDAGPatterns' dtor? (just have a vector of unique_ptrs (maybe even a list or deque of nodes directly owned, rather than via unique_ptr), only create nodes, never destroy them, then destroy them all at the end)</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 10, 2014 at 9:58 PM, wuhui1973 <span dir="ltr"><<a href="mailto:wuhui1973@163.com" target="_blank">wuhui1973@163.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">Hi Andrew, David and Hal:</span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px"><br></span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">I have made a new solution for this memory leak issue, which is much simpler than previous one. </span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px"><br></span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">I have tested it, it works well!</span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px"><br></span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">Please have a look, and appreciate any comment.</span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px"><br></span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">Thanks & Regards</span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px"><br></span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><span style="line-height:23.7999992370605px">Hui Wu</span></div><div style="line-height:1.7;color:rgb(0,0,0);font-size:14px;font-family:Arial"><br></div></div><span title="neteasefooter"><span></span></span></div><br><br><span title="neteasefooter"><span></span></span></blockquote></div><br></div>
</blockquote></div></div></div><br><br><span title="neteasefooter"><span></span></span></blockquote></div><br></div></div>
</blockquote></div></div></div><br><br><span title="neteasefooter"><span></span></span></blockquote></div><br></div>
</div></div></blockquote></div><br><br><span title="neteasefooter"><span></span></span></div><br><br><span title="neteasefooter"><span></span></span></div><br><br><span title="neteasefooter"><span></span></span></blockquote></div><br></div></div>