SlideShare a Scribd company logo
1 of 64
Download to read offline
Avoiding Developer Taxes
(Making development more robust
with introspection tools. )


Stephen.Kennedy @ havok.com
Principal Engineer


github:clang-extract
Awesome Coding




Awesome “Other”     Collecting Awards

                                        2
Awesome
                      Meetings
 Coding


             Refactoring



          Debugging              Awards




                                          3
4
The Classic Game Taxes

Serialization    Memory Reporting



Script Binding     Versioning


                                    5
Memory Lane

10 Years of taxes
Why we changed
Automate
Correctness
Spread the workload

                      6
Structure

Serialization
Reflection
Memory Reporting
Script Binding
Versioning

                   7
Manual serialization
    xtream.TokenMustBe("POINT_A"); xtream>>point_A;
    bool has_two_bodies = true;
    if (xtream.GetVersion() >= 1350)
    {
        xtream.TokenMustBe("HAS_TWO_BODIES"); xtream>>has_two_bodies;
    }
    if (has_two_bodies)
    {
        xtream.TokenMustBe("BODY_B"); xtream>>prot_buffer;
        priv_rigid_body_B = prot_subspace->GetRigidBody(prot_buffer);
        if (!priv_rigid_body_B) throw_exception("Rigidbody unknown in Spring");
    }
    xtream.TokenMustBe("POINT_B"); xtream>>point_B;
    //…

S                                                                                 8
Reflection Recap (1)

struct   A0 { float x; byte y; }
struct   A1 { float z; byte p; byte q };
struct   A2 { byte i[3]; }
…
struct   A1023 { };



S                                          9
Reflection Recap (2)
struct A0 { float x; byte y; }
char A0_type[]={ “FB” };
void save_any( void* obj, char* type )
  while(*type) { switch( *type++ ) {
    case ‘F’:// write(); obj += sizeof(float);
    case ‘B’:// write(); obj += sizeof(bool);
    case 0: return; }
S                                                10
Serialization with Reflection

 Straightforward. (mostly)

 The problem now is …



                                11
Get Reflected

How to reflect our data?

How to keep it up to date?

Robustness

                             12
Manual Reflection
    class Foo {
       public:
                           RTTI_DESCRIBE_CLASS( Foo, (
         enum Flags {…};
                              RTTI_FIELD(i, RTTI_FLD_PUBLIC),
         int i;               RTTI_PTR(pc, RTTI_FLD_PUBLIC),
         char* pc;            RTTI_FIELD(d, RTTI_FLD_PUBLIC),
         double d;            RTTI_FIELD(f, RTTI_FLD_PUBLIC),
         Flags flags;         RTTI_ARRAY(larr, RTTI_FLD_PROTECTED),
                              RTTI_PTR(pa, RTTI_FLD_PROTECTED)
       protected:
                           ) );
         long larr[10];
         A* pa;
    };


R                                                                     13
Parsing Headers
    class Foo {

                                Foo.h
       public:
         int i;
         char* pc;
         double d;
         enum Flags flags;
       protected:             Dirty
         long larr[10];      Regexes
         class B* pb;
         #ifdef PLATFORM_Y
            special* s;
         #endif              FooReflect.cpp
    };
R                                             14
We Went Full Auto

   C++
               Master.h       GCC-XML          DB
headers




     Script1        Script2       Generate
                                  Reflection
 R                                              15
Clang AST Consumer
class RawDumpASTConsumer : public ASTConsumer
{
    virtual void Initialize(ASTContext& Context);
    virtual void HandleTopLevelDecl(DeclGroupRef DG)
    {
        // ...
        if( const FieldDecl* fd = dyn_cast<FieldDecl>(declIn) )
            // ...
        else if( const CXXMethodDecl* md = dyn_cast<CXXMethodDecl>(declIn) )
            // ...
        else if( const EnumConstantDecl* ed = dyn_cast<EnumConstantDecl>(declIn) )
            // ...
    }
};

      R                                                                              16
Clang Custom Output
File( id=20270, location='Base/Types/Geometry/hkGeometry.h' )

RecordType( id=20271, name='hkGeometry', polymorphic=False,
abstract=False, scopeid=20270 )

Method( id=20317, recordid=20271, typeid=20316,
name='getTriangle' )

Field( id=20320, recordid=20271, typeid=9089,
name='m_vertices' )
    R                                                           17
Build Integration

Prebuild step runs Clang if necessary
Plugins run on the database
That’s it               Generate    Reflect.cpp
                       Reflection
ClangAST       DB
                         Static
                        Analysis
   R                                        18
Runtime Introspection
struct X
{                         float
   float time;     bool
   bool used;             float
   float pos;
   bool canmove;   bool           short float
   short flags;                    short    bool bool
};                                       float

    R                                              19
R   20
Reflection Conclusion
LLVM Clang pass
    •   Robust
    •   Eliminates out-of-sync errors
DB Consumer pass
    •   Pre-compile logic checks
    •   Runtime errors → compile errors
Unit Tests
    •   Examine reflection data

                                          21
Language Binding

Expose C++ to script

Data: Natural

Callables: Harder

                       22
Sample Interface

    class Timeline
    {
         /// Adds a label at the given time and
         /// returns an id for that label
       int addLabel( float time, const char* label );
    };

B                                                  23
What is a Binding?
     Lua State
                     int addLabel(
      Lua_String        float time,
         “GDC”          const char* label)
                     {
           Lua_Num       // ...
             1.4     }

B                                            24
Three Parts of a Binding
    Lua State             float time = lua_...
                          char* label = lua_...
       Lua_String
         “GDC”            push time
                Lua_Num   push label
                  1.4     call addLabel
                          pop id
     Lua_Int
     ret = 64
                          lua_set_return( id )
B                                                 25
Manual Bindings
    int wrap_timeLine_addLabel(lua_state* s) {
       TimeLine* tline = lua_checkuserdata(s,1);
       int arg0 = lua_checkint(s,2);
       const char* arg1 = lua_checkstring(s,3);
       int id = tline->addLabel( arg0, arg1 );
       lua_pushint(id);
       return 1;
    }
                timeLine:addLabel(1,”x”)
B                                                  26
Normal “Fat” Bindings

    timeLine:addLabel(1,”x”)
                               1:1 wrapper:native
        wrap_addLabel()        Manual or Generated
                               ~400b per wrapper

     TimeLine::addLabel()
B                                                27
Slimmer Bindings?

    wrap_x()   wrap_z()
                           wrap_any()
           wrap_y()
                          data_x   data_y

         wrap_z()         data_z   data_w

B                                       28
What is a Trampoline?
typedef void (*ErrorFunc)(const char* msg, void* context);
void set_error_function( ErrorFunc func, void* context );

class MyHandler { void on_error(const char* msg) = 0; };

void trampoline(const...;
MyHandler* handler = char* msg, void* context) {
set_error_function( &MyHandler::on_error, handler }
       ((MyErrorHandler*)context)->on_error(msg); );
MyErrorHandler* handler = ...;
set_error_function( &trampoline, handler );

B                                                          29
Reflected Function
struct FunctionReflection {
   const char* name;
   Callable callable; // “function pointer”
   TypeReflection* argTypes;
   int numArgs; // Including return type
};
B                                             30
Slimmer Binding
int wrap_anything(lua_state* s) {
   FunctionReflection* fr = func_get(s);
   Buffer buf;
   unpack_args(s, fr->argTypes, buf);
   (*fr->callable)(buf);
   return pack_args(s, fr->argTypes, buf);
}

B                                            31
Function Trampoline
typedef int (*Func_int__int_charp)(int i, char* c);

void trampoline(void** buf, Func_int__int_charp funcptr)
{
    int& ret = *(int*)buf[0];
    int& a0 = *(int*)buf[1];
    char* a1 = *(char**)buf[2];
    ret = (*funcptr)(a0,a1);
}

B                                                          32
Trampolines
                call_in_lua()

                 lua_bridge()

    trampoline_int()    trampoline_int_charp()


f0(int x)   f1(int x)      native(int,char*)
B                                                33
Fat vs Slim Memory Cost
            N functions
            T distinct trampolines (T≤N)

    N * wrap_func()          1 lua_bridge()    N * Reflection

                            T * trampoline()
      N * func()
                              N * func()


     ~400*N                  ~40*N + ~64*T
B                                                        34
Sharing the Trampolines

tl:addLabel(1,”x”)           tl.addLabel(1,’x’)

    lua_bridge()                  python_bridge()

                   trampoline()

           the_actual_native_function()
B                                                   35
Bindings Conclusion
Generated “Slim” Bindings
     Crossplatform & Multilanguage!
Marginally slower
     Extra indirection
Considerably smaller


                                       36
Memory Reporting Goals

    More than just block sizes
    Account for every byte
    Low maintenance burden
    Customizable output


M                                37
Memory Reporting

Manual getMemoryStatistics()
           void hkpMeshShape::calcContentStatistics
                      ( hkStatisticsCollector* collector ) const
Buggy      {
             collector->addArray( "SubParts", this->m_subparts );
             for( int i = 0; i < this->m_childInfo.getSize(); i++ )
             {
               collector->addReferencedObject( "Child", m_childInfo[i].m_shape );

Tedious
             }
             hkpShapeCollection::calcContentStatistics(collector);
           }



M                                                                            38
Automatic Reports

Aim for 100% automatic coverage
Provide debugging for missing
Leapfrog Technique:
      Remember types of (some) allocations
      Know offsets of pointers in each type



 M                                             39
Raw Blocks


Raw pairs of
(address,size)




 M               40
Type Roots
               ?          BvTree
Hooked class
operator       Mesh   ?       ?
new/delete

               ?


 M                                 41
Reflection Walk
Mesh {         ?            BvTree
 Section [];
};
               Mesh   Section   void
Section {
 Vector4[];
 Indices[];    ?
};
 M                                     42
Reflection Walk
Finds all pointer-to
                     vector4[]         BvTree
relationships

Debug – Time &      Mesh         Section   void
Stacktrace

Verify everything   int[3][]
reached
  M                                               43
Memory Implementation Details

Custom Type Handlers
        slack space – false positives
Obfuscated Pointers
        ptr ^= 1;
Untyped Data
        void*
 M                                       44
Annotated Memory Dump
D   1287169594
M   Win32 “demos.exe"                        #L(ocation) <address> <string name>?
T   0 UNKNOWN                                #C(allstack) <callstack id> <address>+
T   1 hkNativeFileSystem                     #T(ype) <type id> <type name>
C   13 0x29656826 0x29828312 …               #a(llocation) <alloc id> <size>
a   0 8                                      #t(ype instance) <alloc id> <type id>
t   0 1                                      #c(allstack instance) <alloc id> <callstack id>
c   0 13                                     #o(wns) <alloc id> <'owned' alloc id>+
…                                            #M(odule information) <platform-dependent>
o   1 113 9                                  #D(ate of capture) <timestamp>
o   2 193
…
L   0x29656826   sourcecommonbasesystemiofilesystemhknativefilesystem.h(90):'hkNativeFileSystem::operator
new'




    M                                                                                                             45
M   46
Memory Report Conclusion

Label root blocks & grow with reflection
We found offline analysis useful
Low maintenance
Accounts for all reachable memory
     Or tells you where it came from

                                           47
Versioning
    Change Happens

    Hitting a moving target.

    Not much in literature.

V                              48
Manual Conditionals
                            xtream.TokenMustBe("POINT_A"); xtream>>point_A;
                            bool has_two_bodies = true;


    Version number
                            if (xtream.GetVersion()>=1350)
                            {

    Conditionals
                             xtream.TokenMustBe("HAS_TWO_BODIES");
                             xtream>>has_two_bodies;

    Inter-object changes?
                            }
                            if (has_two_bodies)
                            {

    Large refactor?             xtream.TokenMustBe("BODY_B");
                                xtream>>prot_buffer;
                                priv_rigid_body_B = s->GetRigidBody(prot_buffer);
                                if (!priv_rigid_body_B)
                                   throw_exception("Rigidbody unknown in Spring");
                            }
                            xtream.TokenMustBe("POINT_B"); xtream>>point_B;

V
                            //…
                                                                                49
Ideal Versioning System

    Don’t slow me down
    Don’t constrain my changes
    Help me fix it up
    Don’t make me think
    Don’t make me revisit

V                                50
Snapshot Versioning

Compare all previous vs current metadata

Function updates changed members

Check up-to-date with CRC of reflection

V                                          51
Snapshot example
A { int x; int y; }     A { int y; }
B { A* a; }             B { A* a; int x;}

void Update_B( void* oldB, void* newB ) {
  // newB->x = oldB->a->x; }

{ “A”, 0x1234, 0x8989, NULL }
{ “B”, 0xabcd, 0xfed4, Update_B }
V                                           52
Version Function
A { int x; int y; }     A { int y; }
B { A* a; }             B { A* a; int x;}

void Update_B( Object& oldB, Object& newB )
{
  newB[“x”] = oldB[“a”].asObject()[“x”].asInt();
}
V                                              53
Chaining Snapshot Updates


    V1 → V2                                      V2 → Current
    A { int x; int y; }      A { int y; }        A { int y; }             A { int y; int z; }
    B { A* a; }              B { A* a; int x;}   B { A* a; int x; }       B { A* a; int x; }




                                                                                                Current
    void Update_B( void* oldB, void* newB ) {    void Update_A( void* oldA, void* newA ) {
      // newB->x = oldB->a->x; }                   // newA->z = 1000; }


    { “A”, 0x1234, 0x8989, NULL }                { “A”, 0x8989, 0x52c1, Update_A }
    { “B”, 0xabcd, 0xfed4, Update_B }            { “B”, 0xfed4, 0xf115, NULL }




V                                                                                                    54
What Have We Gained?
    Manual                                                                                                                                                                                    if version<1


                                                                                                                             if version<1                                                     if version<2


                                                            if version<1                                                     if version<2                                                     if version<3


     v0                                                        v1                                                               v2                                                            Now

    Snapshots
          A { int x; int y; }           A { int y; }                       A { int x; int y; }           A { int y; }                       A { int x; int y; }           A { int y; }
          B { A* a; }                   B { A* a; int x;}                  B { A* a; }                   B { A* a; int x;}                  B { A* a; }                   B { A* a; int x;}


          void Update_B( void* oldB, void* newB ) {                        void Update_B( void* oldB, void* newB ) {                        void Update_B( void* oldB, void* newB ) {
            // newB->x = oldB->a->x; }                                       // newB->x = oldB->a->x; }                                       // newB->x = oldB->a->x; }


          { “A”, 0x1234, 0x8989, NULL }                                    { “A”, 0x1234, 0x8989, NULL }                                    { “A”, 0x1234, 0x8989, NULL }
          { “B”, 0xabcd, 0xfed4, Update_B }                                { “B”, 0xabcd, 0xfed4, Update_B }                                { “B”, 0xabcd, 0xfed4, Update_B }




     v0                                                        v1                                                               v2                                                            Now
V                                                                                                                                                                                                            55
Finer Grained Changes
We hired artists
Full snapshots too heavy
New products, lots of branches
     •   No global timeline




 V                               56
Patching (1)
A0 { int x; }            A0 { int x; }         A1 { int x; int y; }
B0 { A* a; }             B1 { A* a; int y; }   B2 { A* a; }




        B0→B1
        B.add(int,“y”)



    V                                                            57
Patching (2)
A0 { int x; }            A0 { int x; }          A1 { int x; int y; }
B0 { A* a; }             B1 { A* a; int y; }    B2 { A* a; }



                                      A0→A1
                                      B1→B2
        B0→B1
                                      A.add(int,“y”)
        B.add(int,“y”)
                                      A.y = B.y
                                      B.rem(“y”)
    V                                                             58
Sample Patch
// This block is generated by the metadata comparison.
// It is pasted into the source and expands out to a few constant structures.
PATCH_BEGIN("hkbLookAtModifier", 2, "hkbLookAtModifier", 3)
  // Require hkbEventBase version 3 before running this patch
  PATCH_DEPENDS("hkbEventBase", 3)

 PATCH_MEMBER_ADDED_VEC_4("neckForwardLS", 0.0f,1.0f,0.0f,0.0f)

 // user edit: add & remove changed to rename
 PATCH_MEMBER_RENAMED("headForwardHS", "headForwardLS")

  // user edit: call a C function here
  PATCH_FUNCTION( hkbLookAtModifier_2_to_3 )
PATCH_END()

   V                                                                            59
Verification
 Previous       Apply        Patched
 Reflection    Patches      Reflection




     Patches                Compare
                                           Patches
     Wrong/              against current
                           reflection        OK
     Missing


 V                                             60
Versioning Workflow
Make your changes
Run a reflection diff utility
    Copy & paste the suggested patch
    Edit (add&remove → rename)
    Write version function if necessary
Done
 V                                        61
Versioning Conclusion

Massively reduced tax
Quick to add versioning
Cheap to test
Non-prescriptive workflow


                            62
Data, Not Functions
       Generating code?
            Stop, generate data


       Functions:
            big and single purpose.
       Data:
            small and multi-purpose
                                       63
Conclusion             github:clang-extract

 Reflection   Serialization   Memory



         Binding       Versioning



                                          64

More Related Content

What's hot

Modern c++ (C++ 11/14)
Modern c++ (C++ 11/14)Modern c++ (C++ 11/14)
Modern c++ (C++ 11/14)Geeks Anonymes
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++NextSergey Platonov
 
How to add an optimization for C# to RyuJIT
How to add an optimization for C# to RyuJITHow to add an optimization for C# to RyuJIT
How to add an optimization for C# to RyuJITEgor Bogatov
 
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime
 
Computer Vision using Ruby and libJIT - RubyConf 2009
Computer Vision using Ruby and libJIT - RubyConf 2009Computer Vision using Ruby and libJIT - RubyConf 2009
Computer Vision using Ruby and libJIT - RubyConf 2009Jan Wedekind
 
Dr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slidesDr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slidesDr-archana-dhawan-bajaj
 
STL ALGORITHMS
STL ALGORITHMSSTL ALGORITHMS
STL ALGORITHMSfawzmasood
 
C++11 smart pointer
C++11 smart pointerC++11 smart pointer
C++11 smart pointerLei Yu
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Sergey Platonov
 
from java to c
from java to cfrom java to c
from java to cVõ Hòa
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itEvgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itSergey Platonov
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Sergey Platonov
 
Boost.Python - domesticating the snake
Boost.Python - domesticating the snakeBoost.Python - domesticating the snake
Boost.Python - domesticating the snakeSławomir Zborowski
 
Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Sumant Tambe
 

What's hot (20)

Modern c++ (C++ 11/14)
Modern c++ (C++ 11/14)Modern c++ (C++ 11/14)
Modern c++ (C++ 11/14)
 
Антон Бикинеев, Reflection in C++Next
Антон Бикинеев,  Reflection in C++NextАнтон Бикинеев,  Reflection in C++Next
Антон Бикинеев, Reflection in C++Next
 
How to add an optimization for C# to RyuJIT
How to add an optimization for C# to RyuJITHow to add an optimization for C# to RyuJIT
How to add an optimization for C# to RyuJIT
 
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
 
Computer Vision using Ruby and libJIT - RubyConf 2009
Computer Vision using Ruby and libJIT - RubyConf 2009Computer Vision using Ruby and libJIT - RubyConf 2009
Computer Vision using Ruby and libJIT - RubyConf 2009
 
Dr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slidesDr archana dhawan bajaj - csharp fundamentals slides
Dr archana dhawan bajaj - csharp fundamentals slides
 
OpenGL SC 2.0 Quick Reference
OpenGL SC 2.0 Quick ReferenceOpenGL SC 2.0 Quick Reference
OpenGL SC 2.0 Quick Reference
 
Vulkan 1.1 Reference Guide
Vulkan 1.1 Reference GuideVulkan 1.1 Reference Guide
Vulkan 1.1 Reference Guide
 
STL ALGORITHMS
STL ALGORITHMSSTL ALGORITHMS
STL ALGORITHMS
 
C++11 smart pointer
C++11 smart pointerC++11 smart pointer
C++11 smart pointer
 
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
 
from java to c
from java to cfrom java to c
from java to c
 
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against itEvgeniy Muralev, Mark Vince, Working with the compiler, not against it
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
 
Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++Kirk Shoop, Reactive programming in C++
Kirk Shoop, Reactive programming in C++
 
Idiomatic C++
Idiomatic C++Idiomatic C++
Idiomatic C++
 
Virtual Functions
Virtual FunctionsVirtual Functions
Virtual Functions
 
Boost.Python - domesticating the snake
Boost.Python - domesticating the snakeBoost.Python - domesticating the snake
Boost.Python - domesticating the snake
 
Tiramisu概要
Tiramisu概要Tiramisu概要
Tiramisu概要
 
C++ via C#
C++ via C#C++ via C#
C++ via C#
 
Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)Fun with Lambdas: C++14 Style (part 2)
Fun with Lambdas: C++14 Style (part 2)
 

Similar to 개발 과정 최적화 하기 내부툴로 더욱 강력한 개발하기 Stephen kennedy _(11시40분_103호)

ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersBartosz Kosarzycki
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17LogeekNightUkraine
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Languagemspline
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2goMoriyoshi Koizumi
 
D vs OWKN Language at LLnagoya
D vs OWKN Language at LLnagoyaD vs OWKN Language at LLnagoya
D vs OWKN Language at LLnagoyaN Masahiro
 
Start Wrap Episode 11: A New Rope
Start Wrap Episode 11: A New RopeStart Wrap Episode 11: A New Rope
Start Wrap Episode 11: A New RopeYung-Yu Chen
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesAndrey Karpov
 
C++ amp on linux
C++ amp on linuxC++ amp on linux
C++ amp on linuxMiller Lee
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsBartosz Kosarzycki
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016STX Next
 
Basic c++ 11/14 for python programmers
Basic c++ 11/14 for python programmersBasic c++ 11/14 for python programmers
Basic c++ 11/14 for python programmersJen Yee Hong
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android UpdateGarth Gilmour
 
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)PROIDEA
 
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019corehard_by
 
Zarzadzanie pamiecia w .NET - WDI
Zarzadzanie pamiecia w .NET - WDIZarzadzanie pamiecia w .NET - WDI
Zarzadzanie pamiecia w .NET - WDIKonrad Kokosa
 
The Rust Programming Language: an Overview
The Rust Programming Language: an OverviewThe Rust Programming Language: an Overview
The Rust Programming Language: an OverviewRoberto Casadei
 

Similar to 개발 과정 최적화 하기 내부툴로 더욱 강력한 개발하기 Stephen kennedy _(11시40분_103호) (20)

ADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developersADG Poznań - Kotlin for Android developers
ADG Poznań - Kotlin for Android developers
 
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
Vladymyr Bahrii Understanding polymorphism in C++ 16.11.17
 
C++11: Feel the New Language
C++11: Feel the New LanguageC++11: Feel the New Language
C++11: Feel the New Language
 
All I know about rsc.io/c2go
All I know about rsc.io/c2goAll I know about rsc.io/c2go
All I know about rsc.io/c2go
 
C++11
C++11C++11
C++11
 
D vs OWKN Language at LLnagoya
D vs OWKN Language at LLnagoyaD vs OWKN Language at LLnagoya
D vs OWKN Language at LLnagoya
 
Faster Python, FOSDEM
Faster Python, FOSDEMFaster Python, FOSDEM
Faster Python, FOSDEM
 
Lecture5
Lecture5Lecture5
Lecture5
 
Start Wrap Episode 11: A New Rope
Start Wrap Episode 11: A New RopeStart Wrap Episode 11: A New Rope
Start Wrap Episode 11: A New Rope
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
C++ amp on linux
C++ amp on linuxC++ amp on linux
C++ amp on linux
 
Kotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projectsKotlin Developer Starter in Android projects
Kotlin Developer Starter in Android projects
 
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
Kotlin Developer Starter in Android - STX Next Lightning Talks - Feb 12, 2016
 
Basic c++ 11/14 for python programmers
Basic c++ 11/14 for python programmersBasic c++ 11/14 for python programmers
Basic c++ 11/14 for python programmers
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
4Developers 2018: Evolution of C++ Class Design (Mariusz Łapiński)
 
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
Как работает LLVM бэкенд в C#. Егор Богатов ➠ CoreHard Autumn 2019
 
Zarzadzanie pamiecia w .NET - WDI
Zarzadzanie pamiecia w .NET - WDIZarzadzanie pamiecia w .NET - WDI
Zarzadzanie pamiecia w .NET - WDI
 
The Rust Programming Language: an Overview
The Rust Programming Language: an OverviewThe Rust Programming Language: an Overview
The Rust Programming Language: an Overview
 
C++ Language
C++ LanguageC++ Language
C++ Language
 

More from changehee lee

Gdc 14 bringing unreal engine 4 to open_gl
Gdc 14 bringing unreal engine 4 to open_glGdc 14 bringing unreal engine 4 to open_gl
Gdc 14 bringing unreal engine 4 to open_glchangehee lee
 
Smedberg niklas bringing_aaa_graphics
Smedberg niklas bringing_aaa_graphicsSmedberg niklas bringing_aaa_graphics
Smedberg niklas bringing_aaa_graphicschangehee lee
 
Fortugno nick design_and_monetization
Fortugno nick design_and_monetizationFortugno nick design_and_monetization
Fortugno nick design_and_monetizationchangehee lee
 
[Kgc2013] 모바일 엔진 개발기
[Kgc2013] 모바일 엔진 개발기[Kgc2013] 모바일 엔진 개발기
[Kgc2013] 모바일 엔진 개발기changehee lee
 
모바일 엔진 개발기
모바일 엔진 개발기모바일 엔진 개발기
모바일 엔진 개발기changehee lee
 
Mobile crossplatformchallenges siggraph
Mobile crossplatformchallenges siggraphMobile crossplatformchallenges siggraph
Mobile crossplatformchallenges siggraphchangehee lee
 
개발자여! 스터디를 하자!
개발자여! 스터디를 하자!개발자여! 스터디를 하자!
개발자여! 스터디를 하자!changehee lee
 
[Kgc2012] deferred forward 이창희
[Kgc2012] deferred forward 이창희[Kgc2012] deferred forward 이창희
[Kgc2012] deferred forward 이창희changehee lee
 
Gamificated game developing
Gamificated game developingGamificated game developing
Gamificated game developingchangehee lee
 
Windows to reality getting the most out of direct3 d 10 graphics in your games
Windows to reality   getting the most out of direct3 d 10 graphics in your gamesWindows to reality   getting the most out of direct3 d 10 graphics in your games
Windows to reality getting the most out of direct3 d 10 graphics in your gameschangehee lee
 
Basic ofreflectance kor
Basic ofreflectance korBasic ofreflectance kor
Basic ofreflectance korchangehee lee
 
Valve handbook low_res
Valve handbook low_resValve handbook low_res
Valve handbook low_reschangehee lee
 

More from changehee lee (20)

Visual shock vol.2
Visual shock   vol.2Visual shock   vol.2
Visual shock vol.2
 
Shader compilation
Shader compilationShader compilation
Shader compilation
 
Gdc 14 bringing unreal engine 4 to open_gl
Gdc 14 bringing unreal engine 4 to open_glGdc 14 bringing unreal engine 4 to open_gl
Gdc 14 bringing unreal engine 4 to open_gl
 
Smedberg niklas bringing_aaa_graphics
Smedberg niklas bringing_aaa_graphicsSmedberg niklas bringing_aaa_graphics
Smedberg niklas bringing_aaa_graphics
 
Fortugno nick design_and_monetization
Fortugno nick design_and_monetizationFortugno nick design_and_monetization
Fortugno nick design_and_monetization
 
카툰 렌더링
카툰 렌더링카툰 렌더링
카툰 렌더링
 
[Kgc2013] 모바일 엔진 개발기
[Kgc2013] 모바일 엔진 개발기[Kgc2013] 모바일 엔진 개발기
[Kgc2013] 모바일 엔진 개발기
 
Paper games 2013
Paper games 2013Paper games 2013
Paper games 2013
 
모바일 엔진 개발기
모바일 엔진 개발기모바일 엔진 개발기
모바일 엔진 개발기
 
V8
V8V8
V8
 
Wecanmakeengine
WecanmakeengineWecanmakeengine
Wecanmakeengine
 
Mobile crossplatformchallenges siggraph
Mobile crossplatformchallenges siggraphMobile crossplatformchallenges siggraph
Mobile crossplatformchallenges siggraph
 
개발자여! 스터디를 하자!
개발자여! 스터디를 하자!개발자여! 스터디를 하자!
개발자여! 스터디를 하자!
 
[Kgc2012] deferred forward 이창희
[Kgc2012] deferred forward 이창희[Kgc2012] deferred forward 이창희
[Kgc2012] deferred forward 이창희
 
Light prepass
Light prepassLight prepass
Light prepass
 
Gamificated game developing
Gamificated game developingGamificated game developing
Gamificated game developing
 
Windows to reality getting the most out of direct3 d 10 graphics in your games
Windows to reality   getting the most out of direct3 d 10 graphics in your gamesWindows to reality   getting the most out of direct3 d 10 graphics in your games
Windows to reality getting the most out of direct3 d 10 graphics in your games
 
Basic ofreflectance kor
Basic ofreflectance korBasic ofreflectance kor
Basic ofreflectance kor
 
C++11(최지웅)
C++11(최지웅)C++11(최지웅)
C++11(최지웅)
 
Valve handbook low_res
Valve handbook low_resValve handbook low_res
Valve handbook low_res
 

개발 과정 최적화 하기 내부툴로 더욱 강력한 개발하기 Stephen kennedy _(11시40분_103호)

  • 1. Avoiding Developer Taxes (Making development more robust with introspection tools. ) Stephen.Kennedy @ havok.com Principal Engineer github:clang-extract
  • 3. Awesome Meetings Coding Refactoring Debugging Awards 3
  • 4. 4
  • 5. The Classic Game Taxes Serialization Memory Reporting Script Binding Versioning 5
  • 6. Memory Lane 10 Years of taxes Why we changed Automate Correctness Spread the workload 6
  • 8. Manual serialization xtream.TokenMustBe("POINT_A"); xtream>>point_A; bool has_two_bodies = true; if (xtream.GetVersion() >= 1350) { xtream.TokenMustBe("HAS_TWO_BODIES"); xtream>>has_two_bodies; } if (has_two_bodies) { xtream.TokenMustBe("BODY_B"); xtream>>prot_buffer; priv_rigid_body_B = prot_subspace->GetRigidBody(prot_buffer); if (!priv_rigid_body_B) throw_exception("Rigidbody unknown in Spring"); } xtream.TokenMustBe("POINT_B"); xtream>>point_B; //… S 8
  • 9. Reflection Recap (1) struct A0 { float x; byte y; } struct A1 { float z; byte p; byte q }; struct A2 { byte i[3]; } … struct A1023 { }; S 9
  • 10. Reflection Recap (2) struct A0 { float x; byte y; } char A0_type[]={ “FB” }; void save_any( void* obj, char* type ) while(*type) { switch( *type++ ) { case ‘F’:// write(); obj += sizeof(float); case ‘B’:// write(); obj += sizeof(bool); case 0: return; } S 10
  • 11. Serialization with Reflection Straightforward. (mostly) The problem now is … 11
  • 12. Get Reflected How to reflect our data? How to keep it up to date? Robustness 12
  • 13. Manual Reflection class Foo { public: RTTI_DESCRIBE_CLASS( Foo, ( enum Flags {…}; RTTI_FIELD(i, RTTI_FLD_PUBLIC), int i; RTTI_PTR(pc, RTTI_FLD_PUBLIC), char* pc; RTTI_FIELD(d, RTTI_FLD_PUBLIC), double d; RTTI_FIELD(f, RTTI_FLD_PUBLIC), Flags flags; RTTI_ARRAY(larr, RTTI_FLD_PROTECTED), RTTI_PTR(pa, RTTI_FLD_PROTECTED) protected: ) ); long larr[10]; A* pa; }; R 13
  • 14. Parsing Headers class Foo { Foo.h public: int i; char* pc; double d; enum Flags flags; protected: Dirty long larr[10]; Regexes class B* pb; #ifdef PLATFORM_Y special* s; #endif FooReflect.cpp }; R 14
  • 15. We Went Full Auto C++ Master.h GCC-XML DB headers Script1 Script2 Generate Reflection R 15
  • 16. Clang AST Consumer class RawDumpASTConsumer : public ASTConsumer { virtual void Initialize(ASTContext& Context); virtual void HandleTopLevelDecl(DeclGroupRef DG) { // ... if( const FieldDecl* fd = dyn_cast<FieldDecl>(declIn) ) // ... else if( const CXXMethodDecl* md = dyn_cast<CXXMethodDecl>(declIn) ) // ... else if( const EnumConstantDecl* ed = dyn_cast<EnumConstantDecl>(declIn) ) // ... } }; R 16
  • 17. Clang Custom Output File( id=20270, location='Base/Types/Geometry/hkGeometry.h' ) RecordType( id=20271, name='hkGeometry', polymorphic=False, abstract=False, scopeid=20270 ) Method( id=20317, recordid=20271, typeid=20316, name='getTriangle' ) Field( id=20320, recordid=20271, typeid=9089, name='m_vertices' ) R 17
  • 18. Build Integration Prebuild step runs Clang if necessary Plugins run on the database That’s it Generate Reflect.cpp Reflection ClangAST DB Static Analysis R 18
  • 19. Runtime Introspection struct X { float float time; bool bool used; float float pos; bool canmove; bool short float short flags; short bool bool }; float R 19
  • 20. R 20
  • 21. Reflection Conclusion LLVM Clang pass • Robust • Eliminates out-of-sync errors DB Consumer pass • Pre-compile logic checks • Runtime errors → compile errors Unit Tests • Examine reflection data 21
  • 22. Language Binding Expose C++ to script Data: Natural Callables: Harder 22
  • 23. Sample Interface class Timeline { /// Adds a label at the given time and /// returns an id for that label int addLabel( float time, const char* label ); }; B 23
  • 24. What is a Binding? Lua State int addLabel( Lua_String float time, “GDC” const char* label) { Lua_Num // ... 1.4 } B 24
  • 25. Three Parts of a Binding Lua State float time = lua_... char* label = lua_... Lua_String “GDC” push time Lua_Num push label 1.4 call addLabel pop id Lua_Int ret = 64 lua_set_return( id ) B 25
  • 26. Manual Bindings int wrap_timeLine_addLabel(lua_state* s) { TimeLine* tline = lua_checkuserdata(s,1); int arg0 = lua_checkint(s,2); const char* arg1 = lua_checkstring(s,3); int id = tline->addLabel( arg0, arg1 ); lua_pushint(id); return 1; } timeLine:addLabel(1,”x”) B 26
  • 27. Normal “Fat” Bindings timeLine:addLabel(1,”x”) 1:1 wrapper:native wrap_addLabel() Manual or Generated ~400b per wrapper TimeLine::addLabel() B 27
  • 28. Slimmer Bindings? wrap_x() wrap_z() wrap_any() wrap_y() data_x data_y wrap_z() data_z data_w B 28
  • 29. What is a Trampoline? typedef void (*ErrorFunc)(const char* msg, void* context); void set_error_function( ErrorFunc func, void* context ); class MyHandler { void on_error(const char* msg) = 0; }; void trampoline(const...; MyHandler* handler = char* msg, void* context) { set_error_function( &MyHandler::on_error, handler } ((MyErrorHandler*)context)->on_error(msg); ); MyErrorHandler* handler = ...; set_error_function( &trampoline, handler ); B 29
  • 30. Reflected Function struct FunctionReflection { const char* name; Callable callable; // “function pointer” TypeReflection* argTypes; int numArgs; // Including return type }; B 30
  • 31. Slimmer Binding int wrap_anything(lua_state* s) { FunctionReflection* fr = func_get(s); Buffer buf; unpack_args(s, fr->argTypes, buf); (*fr->callable)(buf); return pack_args(s, fr->argTypes, buf); } B 31
  • 32. Function Trampoline typedef int (*Func_int__int_charp)(int i, char* c); void trampoline(void** buf, Func_int__int_charp funcptr) { int& ret = *(int*)buf[0]; int& a0 = *(int*)buf[1]; char* a1 = *(char**)buf[2]; ret = (*funcptr)(a0,a1); } B 32
  • 33. Trampolines call_in_lua() lua_bridge() trampoline_int() trampoline_int_charp() f0(int x) f1(int x) native(int,char*) B 33
  • 34. Fat vs Slim Memory Cost N functions T distinct trampolines (T≤N) N * wrap_func() 1 lua_bridge() N * Reflection T * trampoline() N * func() N * func() ~400*N ~40*N + ~64*T B 34
  • 35. Sharing the Trampolines tl:addLabel(1,”x”) tl.addLabel(1,’x’) lua_bridge() python_bridge() trampoline() the_actual_native_function() B 35
  • 36. Bindings Conclusion Generated “Slim” Bindings  Crossplatform & Multilanguage! Marginally slower  Extra indirection Considerably smaller 36
  • 37. Memory Reporting Goals More than just block sizes Account for every byte Low maintenance burden Customizable output M 37
  • 38. Memory Reporting Manual getMemoryStatistics() void hkpMeshShape::calcContentStatistics ( hkStatisticsCollector* collector ) const Buggy { collector->addArray( "SubParts", this->m_subparts ); for( int i = 0; i < this->m_childInfo.getSize(); i++ ) { collector->addReferencedObject( "Child", m_childInfo[i].m_shape ); Tedious } hkpShapeCollection::calcContentStatistics(collector); } M 38
  • 39. Automatic Reports Aim for 100% automatic coverage Provide debugging for missing Leapfrog Technique:  Remember types of (some) allocations  Know offsets of pointers in each type M 39
  • 40. Raw Blocks Raw pairs of (address,size) M 40
  • 41. Type Roots ? BvTree Hooked class operator Mesh ? ? new/delete ? M 41
  • 42. Reflection Walk Mesh { ? BvTree Section []; }; Mesh Section void Section { Vector4[]; Indices[]; ? }; M 42
  • 43. Reflection Walk Finds all pointer-to vector4[] BvTree relationships Debug – Time & Mesh Section void Stacktrace Verify everything int[3][] reached M 43
  • 44. Memory Implementation Details Custom Type Handlers  slack space – false positives Obfuscated Pointers  ptr ^= 1; Untyped Data  void* M 44
  • 45. Annotated Memory Dump D 1287169594 M Win32 “demos.exe" #L(ocation) <address> <string name>? T 0 UNKNOWN #C(allstack) <callstack id> <address>+ T 1 hkNativeFileSystem #T(ype) <type id> <type name> C 13 0x29656826 0x29828312 … #a(llocation) <alloc id> <size> a 0 8 #t(ype instance) <alloc id> <type id> t 0 1 #c(allstack instance) <alloc id> <callstack id> c 0 13 #o(wns) <alloc id> <'owned' alloc id>+ … #M(odule information) <platform-dependent> o 1 113 9 #D(ate of capture) <timestamp> o 2 193 … L 0x29656826 sourcecommonbasesystemiofilesystemhknativefilesystem.h(90):'hkNativeFileSystem::operator new' M 45
  • 46. M 46
  • 47. Memory Report Conclusion Label root blocks & grow with reflection We found offline analysis useful Low maintenance Accounts for all reachable memory  Or tells you where it came from 47
  • 48. Versioning Change Happens Hitting a moving target. Not much in literature. V 48
  • 49. Manual Conditionals xtream.TokenMustBe("POINT_A"); xtream>>point_A; bool has_two_bodies = true; Version number if (xtream.GetVersion()>=1350) { Conditionals xtream.TokenMustBe("HAS_TWO_BODIES"); xtream>>has_two_bodies; Inter-object changes? } if (has_two_bodies) { Large refactor? xtream.TokenMustBe("BODY_B"); xtream>>prot_buffer; priv_rigid_body_B = s->GetRigidBody(prot_buffer); if (!priv_rigid_body_B) throw_exception("Rigidbody unknown in Spring"); } xtream.TokenMustBe("POINT_B"); xtream>>point_B; V //… 49
  • 50. Ideal Versioning System Don’t slow me down Don’t constrain my changes Help me fix it up Don’t make me think Don’t make me revisit V 50
  • 51. Snapshot Versioning Compare all previous vs current metadata Function updates changed members Check up-to-date with CRC of reflection V 51
  • 52. Snapshot example A { int x; int y; } A { int y; } B { A* a; } B { A* a; int x;} void Update_B( void* oldB, void* newB ) { // newB->x = oldB->a->x; } { “A”, 0x1234, 0x8989, NULL } { “B”, 0xabcd, 0xfed4, Update_B } V 52
  • 53. Version Function A { int x; int y; } A { int y; } B { A* a; } B { A* a; int x;} void Update_B( Object& oldB, Object& newB ) { newB[“x”] = oldB[“a”].asObject()[“x”].asInt(); } V 53
  • 54. Chaining Snapshot Updates V1 → V2 V2 → Current A { int x; int y; } A { int y; } A { int y; } A { int y; int z; } B { A* a; } B { A* a; int x;} B { A* a; int x; } B { A* a; int x; } Current void Update_B( void* oldB, void* newB ) { void Update_A( void* oldA, void* newA ) { // newB->x = oldB->a->x; } // newA->z = 1000; } { “A”, 0x1234, 0x8989, NULL } { “A”, 0x8989, 0x52c1, Update_A } { “B”, 0xabcd, 0xfed4, Update_B } { “B”, 0xfed4, 0xf115, NULL } V 54
  • 55. What Have We Gained? Manual if version<1 if version<1 if version<2 if version<1 if version<2 if version<3 v0 v1 v2 Now Snapshots A { int x; int y; } A { int y; } A { int x; int y; } A { int y; } A { int x; int y; } A { int y; } B { A* a; } B { A* a; int x;} B { A* a; } B { A* a; int x;} B { A* a; } B { A* a; int x;} void Update_B( void* oldB, void* newB ) { void Update_B( void* oldB, void* newB ) { void Update_B( void* oldB, void* newB ) { // newB->x = oldB->a->x; } // newB->x = oldB->a->x; } // newB->x = oldB->a->x; } { “A”, 0x1234, 0x8989, NULL } { “A”, 0x1234, 0x8989, NULL } { “A”, 0x1234, 0x8989, NULL } { “B”, 0xabcd, 0xfed4, Update_B } { “B”, 0xabcd, 0xfed4, Update_B } { “B”, 0xabcd, 0xfed4, Update_B } v0 v1 v2 Now V 55
  • 56. Finer Grained Changes We hired artists Full snapshots too heavy New products, lots of branches • No global timeline V 56
  • 57. Patching (1) A0 { int x; } A0 { int x; } A1 { int x; int y; } B0 { A* a; } B1 { A* a; int y; } B2 { A* a; } B0→B1 B.add(int,“y”) V 57
  • 58. Patching (2) A0 { int x; } A0 { int x; } A1 { int x; int y; } B0 { A* a; } B1 { A* a; int y; } B2 { A* a; } A0→A1 B1→B2 B0→B1 A.add(int,“y”) B.add(int,“y”) A.y = B.y B.rem(“y”) V 58
  • 59. Sample Patch // This block is generated by the metadata comparison. // It is pasted into the source and expands out to a few constant structures. PATCH_BEGIN("hkbLookAtModifier", 2, "hkbLookAtModifier", 3) // Require hkbEventBase version 3 before running this patch PATCH_DEPENDS("hkbEventBase", 3) PATCH_MEMBER_ADDED_VEC_4("neckForwardLS", 0.0f,1.0f,0.0f,0.0f) // user edit: add & remove changed to rename PATCH_MEMBER_RENAMED("headForwardHS", "headForwardLS") // user edit: call a C function here PATCH_FUNCTION( hkbLookAtModifier_2_to_3 ) PATCH_END() V 59
  • 60. Verification Previous Apply Patched Reflection Patches Reflection Patches Compare Patches Wrong/ against current reflection OK Missing V 60
  • 61. Versioning Workflow Make your changes Run a reflection diff utility Copy & paste the suggested patch Edit (add&remove → rename) Write version function if necessary Done V 61
  • 62. Versioning Conclusion Massively reduced tax Quick to add versioning Cheap to test Non-prescriptive workflow 62
  • 63. Data, Not Functions Generating code?  Stop, generate data Functions:  big and single purpose. Data:  small and multi-purpose 63
  • 64. Conclusion github:clang-extract Reflection Serialization Memory Binding Versioning 64