This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] [2nd version] GCC support for live-patching


Hi, 

this is the 2nd version of the proposal. the major changes are:

1.  change the option name from “-fease-live-patching” to “-flive-patching”
2.  delete two sub-options, “none”, “inline” from the list, only keep “inline-only-static” and “inline-clone”.
3.  add the importance of controlling the number of impacted function list to control memory consumption for
     live patching schemes that patch hundreds or thousands processes at the same time.
4.  re-organize the background and motivation sections based on the previous feedbacks. 

Please take a look and let me know any more comments and suggestions.

thanks.

Qing

====================================

options to help live patching in GCC (version 2)

Qing Zhao

10/31/2018
================================================

0. Terminology used in this proposal
1. The proposal
2. Two issues in live patching schemes that need compiler support 
3. Compiler support for live patching
4. Details of the proposal


0. Terminology used in this proposal:

 impacted function:

 When the body or the information extracted from the body of a function is 
used to optimize and change another function, the latter is called an impacted 
function of the former. 

 impacted function list:

 A list that includes all the impacted functions for a specific function. 

1. The proposal:

Provide two first class options in GCC to help live-patching users.

A. an option to control GCC's optimizations to provide a safe 
compilation for live-patching purpose. At the same time, provides
multiple-level control on the length of the impacted function list 
and run time performance tradeoff.

-flive-patching={inline-only-static | inline-clone}

When -flive-patching specified without any value, the default value
is "inline-clone". 

B. an option to compute the impacted function lists and dump them for
live-patching users.  

-flive-patching-list={func_name | all}{,dump_func_name}

This option guides the compiler to compute the list of impacted routines for
live patching. It only has effect when it is combined with -flive-patching.

when -flive-patching-list is specified without any value, the default value is
"all", i.e, compute the lists of impacted functions for all functions and dump 
them into stdout for the specific -flive-patching option.

Refer to Section 4 for more details of the proposal.

2. Two issues in live patching schemes that need compiler support: 

There are two major issues that need compilers' support in live patching:

   A. control the number of impacted functions;
   B. compute and report the impacted function list;

A is for the live patching scheme that patches hundreds or thousands
multiple-processes in order to control the total memory consumption. 
B is for the live patching scheme that generates patches from
source code level.  

The following is the detailed explanation of these two issues.

2.1. compute and report the impacted function list 

There are three major kernel live patching tools:  
(https://lwn.net/Articles/734765/ <https://lwn.net/Articles/734765/>)

* ksplice:   http://www.ksplice.com/doc/ksplice.pdf <http://www.ksplice.com/doc/ksplice.pdf>
* kpatch:    https://lwn.net/Articles/597123/ <https://lwn.net/Articles/597123/>
            https://github.com/dynup/kpatch <https://github.com/dynup/kpatch>
* kGraft:    
https://pdfs.semanticscholar.org/presentation/af4c/895aa3fef0cc2b501317aaec9d91ba2d704c.pdf <https://pdfs.semanticscholar.org/presentation/af4c/895aa3fef0cc2b501317aaec9d91ba2d704c.pdf>

They can be classified into two groups depending on the ways to generate
the patches:

   Group A: generate patches at binary level. the binary patches can be 
     automatically generated as following: 
     a collection of tools which convert a source diff patch to a patch
     module. They work by compiling the kernel both with and without the source
     patch, comparing the binaries, and generating a binary patch module which 
     includes new binary versions of the functions to be replaced.
     Group A includes ksplice and kpatch.

   Group B: generate patches at source code level. The source of the patch
     will be in a single C file, which is created entirely by hand. This C file
     will be compiled into the final patch module. 
     Group B includes kGraft. 

The major benefit of the live patching scheme in Group B is, the patches will be
easy to review, easy to maintain since they are C files. 

Taking kGraft as an example, Source code level patch creation involves the 
following three steps: 
(From Nicolai Stange: nstange@suse.de <mailto:nstange@suse.de>)

Step 1. Determine the initial set of to be patched functions:
 a.) Inspect the diff for the fix in question, add any touched 
     functions to the initial set.
 b.) For each function in the initial set, check whether it has been
     used by compiler analyses/optimizations to change other functions,
     an impacted function should be patched at the same time as the 
     original one. add the impacted functions to the initial set.
     Repeat until the initial set has been stabilized.

Step 2. Copy & paste the initial set over to the new live patch sources.

Step 3. Make it compile, i.e. recursively copy any needed cpp macro, type, 
 or functions definition and add references to data objects with static
 storage duration.

The above Step 1b is the first place that needs compiler support
to compute and report the list of impacted functions for each function.

2.2. Control the number of impacted functions

When the above linux kernel live patching schemes involve modification of only 
a single copy of text, there are live patching schemes for other applications
that have to patch thousands of user processes simultaneously. For such live
patching scheme, the number of patched functions has a large impact on the size
of used memory. Basically, the OS will have to make a private copy of each page 
that is modified in a process's text segment. The more functions that are patched,
the more likely it is that additional pages will have to be modified. When the
number of processes is huge, it's important to minimize amount of private memory 
consumed by each process. Therefore, it's important to control the number of 
patched functions.

There are mainly two factors to decide the number of patched functions:

   1) the initial set of patched functions;
   2) the impacted functions for each of the functions in 1). 

The above 2) is the place that needs compiler support to control the number 
of impacted functions. 

3. Compiler support for live patching.

As identified in the above section, live patching needs compiler support 
for the following two issues:

   A. control the number of impacted functions;
   B. compute and report the impacted function list;

The impacted functions are decided by the compiler optimizations that use
the body or the information extracted from the body of a function to change
other functions. Such compiler optimizations are usually IPA optimizations. 
For example, inlining a function into it's caller, cloning a function and
changing it's caller to call this new clone, or extracting a function's 
pureness/constness information to optimize it's direct or indirect callers,
etc. 

Usually, the more IPA optimizations enabled, the larger the number of
impacted functions for each function. In order to control the number of 
impacted functions, we should provide control to partially enable IPA
optimizations on different levels. 

Only for enabled IPA optimization, we compute and report the impacted function
list for each function. all the other IPA optimizations should be disabled.

currently, we have requests for the following two levels of control:

  level 1:  inline-only-static
  only enable inlining of static functions, disable all other IPA optimizations.
  This is mainly for the live patching user who has to patch thousands of 
  processes simutaniously to control the memory consumption.

  level 2:  inline-clone
  Only enable inlining and all optimizations that internally create clone,
  for example, cloning, ipa-sra, partial inlining, etc.; disable all
  other IPA optimizations/analyses. 

  This is manly for the live patching users who create patches on source code
  level.

We can definitely extend to other levels later if needed. If run-time performance
is critical, more IPA optimizations need to be enabled; On the other hand, 
if memory consumption is more critical, less IPA optimizations need to be enabled.

4. Details of the proposal:

What should GCC provide to live-patching users? 

A. an option to control GCC's optimizations to provide a safe 
compilation for live-patching purpose. At the same time, provides
multiple-level control on the length of the impacted function list 
and run time performance tradeoff.

-flive-patching={only-inline-static|inline-clone}

-flive-patching=only-inline-static

  Only enable inlining of static functions, disable all other IPA 
optimizations/analyses. As a result, when patching a static routine,
all its callers need to be patches as well.

-flive-patching=inline-clone

  Only enable inlining and all optimizations that internally create clone,
for example, cloning, ipa-sra, partial inlining, etc.; disable all 
other IPA optimizations/analyses.
  As a result, when patching a routine, all its callers and its clones'
callers need to be patched as well. 

When -flive-patching specified without any value, the default value
is "inline-clone". 

B. an option to compute the impacted function lists and dump them for
live-patching users.  

-flive-patching-list={func_name|all}{,dump_func_name}

This option guides the compiler to compute the list of impacted routines for
live patching. It only has effect when it is combined with -flive-patching.

-flive-patching-list=func_name

compute the list of impacted routines for the routine "func_name" and dump it
into stdout.

-flive-patching-list=all

compute the list of impacted routines for all routines and dump them 
into stdout.

-flive-patching-list=func_name,dump_func_name

compute the list of impacted routines for the routine "func_name" and dump it
into the file "dump_func_name".

-flive-patching-list=all,dump_func_name

compute the list of impacted routines for all routines and dump them 
into the file "dump_func_name".

when -flive-patching-list is specified without any value, the default value is
"all", i.e, compute the lists of impacted routines for all routinesand dump 
them into stdout.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]