Changeset 2f19e03
- Timestamp:
- Jun 15, 2021, 12:28:48 PM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- b51e389c
- Parents:
- 4aba055 (diff), 4f1b8f3f (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 7 added
- 20 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
Jenkins/Distribute
r4aba055 r2f19e03 2 2 3 3 import groovy.transform.Field 4 5 // For skipping stages6 import org.jenkinsci.plugins.pipeline.modeldefinition.Utils7 4 8 5 //=========================================================================================================== … … 10 7 //=========================================================================================================== 11 8 12 node('master') { 13 // Globals 14 BuildDir = pwd tmp: true 15 SrcDir = pwd tmp: false 16 Settings = null 17 Version = '' 9 // Globals 10 BuildDir = null 11 SrcDir = null 12 Settings = null 13 Version = '' 18 14 19 20 21 15 // Local variables 16 def err = null 17 def log_needed = false 22 18 23 currentBuild.result = "SUCCESS" 19 currentBuild.result = "SUCCESS" 20 21 final commit, build 22 node { 24 23 25 24 //Wrap build to add timestamp to command line 26 25 wrap([$class: 'TimestamperBuildWrapper']) { 26 (commit, build) = prepare_build() 27 } 28 } 27 29 28 final commit, build 29 (commit, build) = prepare_build() 30 31 node('x64') { 32 BuildDir = pwd tmp: true 33 SrcDir = pwd tmp: false 34 35 Tools.Clean() 36 37 Tools.Checkout( commit ) 38 39 Version = GetVersion( build ) 40 41 Configure() 42 43 Package() 44 45 Test() 46 47 Archive() 48 } 49 50 // Update the build directories when exiting the node 30 node('x64') { 31 //Wrap build to add timestamp to command line 32 wrap([$class: 'TimestamperBuildWrapper']) { 51 33 BuildDir = pwd tmp: true 52 34 SrcDir = pwd tmp: false 35 36 Tools.Clean() 37 38 Tools.Checkout( commit ) 39 40 Version = GetVersion( build ) 41 42 Configure() 43 44 Package() 45 46 Test() 47 48 Archive() 53 49 } 54 55 50 } 56 51 -
Jenkins/FullBuild
r4aba055 r2f19e03 5 5 //=========================================================================================================== 6 6 7 node ('master'){7 node { 8 8 def err = null 9 9 … … 106 106 107 107 if(result.result != 'SUCCESS') { 108 sh("wget -q -O - http ://localhost:8084/jenkins/job/Cforall/job/master/${result.number}/consoleText")108 sh("wget -q -O - https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/${result.number}/consoleText") 109 109 error(result.result) 110 110 } … … 144 144 //Email notification on a full build failure 145 145 def promote_email(boolean success) { 146 echo('notifying users') 146 node { 147 echo('notifying users') 147 148 148 def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE"149 def result = success ? "PROMOTE - SUCCESS" : "PROMOTE - FAILURE" 149 150 150 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line151 //Configurations for email format152 def email_subject = "[cforall git][${result}]"153 def email_body = """<p>This is an automated email from the Jenkins build machine. It was154 generated following the result of the C\u2200 nightly build.</p>151 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 152 //Configurations for email format 153 def email_subject = "[cforall git][${result}]" 154 def email_body = """<p>This is an automated email from the Jenkins build machine. It was 155 generated following the result of the C\u2200 nightly build.</p> 155 156 156 <p>Check console output at ${env.BUILD_URL} to view the results.</p>157 <p>Check console output at ${env.BUILD_URL} to view the results.</p> 157 158 158 <p>- Status --------------------------------------------------------------</p>159 <p>- Status --------------------------------------------------------------</p> 159 160 160 <p>${result}</p>161 <p>${result}</p> 161 162 162 <p>- Performance ---------------------------------------------------------</p>163 <p>- Performance ---------------------------------------------------------</p> 163 164 164 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=0" >165 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=1" >165 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=0" > 166 <img src="https://cforall.uwaterloo.ca/jenkins/job/Cforall/job/master/plot/Compilation/getPlot?index=1" > 166 167 167 <p>- Logs ----------------------------------------------------------------</p>168 """168 <p>- Logs ----------------------------------------------------------------</p> 169 """ 169 170 170 def email_to = "cforall@lists.uwaterloo.ca"171 def email_to = "cforall@lists.uwaterloo.ca" 171 172 172 //send email notification 173 emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success 173 //send email notification 174 emailext body: email_body, subject: email_subject, to: email_to, attachLog: !success 175 } 174 176 } -
Jenkins/tools.groovy
r4aba055 r2f19e03 61 61 } 62 62 63 PrevGitOldRef = '' 64 PrevGitNewRef = '' 65 def GitLogMessage(String oldRef = '', String newRef = '') { 66 if (!oldRef) { if(!PrevGitOldRef) { return "\nERROR retrieveing current git information!\n" } else { oldRef = PrevGitOldRef } } 67 if (!newRef) { if(!PrevGitNewRef) { return "\nERROR retrieveing previous git information!\n" } else { newRef = PrevGitNewRef } } 68 63 def ConstructGitLogMessage(String oldRef, String newRef) { 69 64 def revText = sh(returnStdout: true, script: "git rev-list ${oldRef}..${newRef}").trim() 70 65 def revList = SplitLines( revText ) … … 87 82 gitDiff = gitDiff.replace('[m', '</span>') 88 83 89 PrevGitOldRef = oldRef90 PrevGitNewRef = newRef 84 return """ 85 <p>- Changes -------------------------------------------------------------</p> 91 86 92 return """93 87 <pre> 94 88 The branch ${env.BRANCH_NAME} has been updated. 95 89 ${gitUpdate} 96 90 </pre> 97 98 <p>Check console output at ${env.BUILD_URL} to view the results.</p>99 100 <p>- Status --------------------------------------------------------------</p>101 102 <p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>103 91 104 92 <p>- Log -----------------------------------------------------------------</p> … … 116 104 } 117 105 106 EmailMessage = '' 107 def GitLogMessage(String oldRef = '', String newRef = '') { 108 if(!EmailMessage) { 109 if (!oldRef) { return "\nERROR retrieveing current git information!\n" } 110 if (!newRef) { return "\nERROR retrieveing previous git information!\n" } 111 112 echo "Constructing new git message" 113 114 EmailMessage = ConstructGitLogMessage(oldRef, newRef) 115 } 116 else { 117 echo "Reusing previously constructed message" 118 } 119 return EmailMessage; 120 } 121 118 122 return this; -
Jenkinsfile
r4aba055 r2f19e03 7 7 //=========================================================================================================== 8 8 9 node('master') { 10 // Globals 11 BuildDir = pwd tmp: true 12 SrcDir = pwd tmp: false 13 Settings= null14 Tools = null 15 16 // Local variables 17 def err = null 18 def log_needed = false 19 20 currentBuild.result = "SUCCESS" 21 22 try{9 // Globals 10 BuildDir = null 11 SrcDir = null 12 Settings = null 13 Tools = null 14 15 // Local variables 16 def err = null 17 def log_needed = false 18 19 currentBuild.result = "SUCCESS" 20 21 try { 22 node { 23 23 //Wrap build to add timestamp to command line 24 24 wrap([$class: 'TimestamperBuildWrapper']) { 25 26 25 Settings = prepare_build() 27 28 node(Settings.Architecture.node) { 29 BuildDir = pwd tmp: true 30 SrcDir = pwd tmp: false 31 currentBuild.description = "${currentBuild.description} on ${env.NODE_NAME}" 32 33 Tools.Clean() 34 35 Tools.Checkout() 36 37 build() 38 39 test() 40 41 benchmark() 42 43 build_doc() 44 45 publish() 46 } 47 48 // Update the build directories when exiting the node 26 } 27 } 28 29 node(Settings.Architecture.node) { 30 //Wrap build to add timestamp to command line 31 wrap([$class: 'TimestamperBuildWrapper']) { 49 32 BuildDir = pwd tmp: true 50 33 SrcDir = pwd tmp: false 51 } 52 } 53 54 //If an exception is caught we need to change the status and remember to 55 //attach the build log to the email 56 catch (Exception caughtError) { 57 // Store the result of the build log 58 currentBuild.result = "FAILURE" 59 60 // An error has occured, the build log is relevent 61 log_needed = true 62 63 // rethrow error later 64 err = caughtError 65 66 // print the error so it shows in the log 67 echo err.toString() 68 } 69 70 finally { 71 //Send email with final results if this is not a full build 72 email(log_needed) 73 74 echo 'Build Completed' 75 76 /* Must re-throw exception to propagate error */ 77 if (err) { 78 throw err 79 } 34 currentBuild.description = "${currentBuild.description} on ${env.NODE_NAME}" 35 36 Tools.Clean() 37 38 Tools.Checkout() 39 40 build() 41 42 test() 43 44 benchmark() 45 46 build_doc() 47 48 publish() 49 } 50 } 51 } 52 53 //If an exception is caught we need to change the status and remember to 54 //attach the build log to the email 55 catch (Exception caughtError) { 56 // Store the result of the build log 57 currentBuild.result = "FAILURE" 58 59 // An error has occured, the build log is relevent 60 log_needed = true 61 62 // rethrow error later 63 err = caughtError 64 65 // print the error so it shows in the log 66 echo err.toString() 67 } 68 69 finally { 70 //Send email with final results if this is not a full build 71 email(log_needed) 72 73 echo 'Build Completed' 74 75 /* Must re-throw exception to propagate error */ 76 if (err) { 77 throw err 80 78 } 81 79 } … … 228 226 //Standard build email notification 229 227 def email(boolean log) { 230 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 231 //Configurations for email format 232 echo 'Notifying users of result' 233 234 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase() 235 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}" 236 def email_body = """<p>This is an automated email from the Jenkins build machine. It was 237 generated because of a git hooks/post-receive script following 238 a ref change which was pushed to the C\u2200 repository.</p> 239 """ + Tools.GitLogMessage() 240 241 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca" 242 243 if( Settings && !Settings.Silent ) { 244 //send email notification 245 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log 246 } else { 247 echo "Would send email to: ${email_to}" 248 echo "With title: ${email_subject}" 249 echo "Content: \n${email_body}" 228 node { 229 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line 230 //Configurations for email format 231 echo 'Notifying users of result' 232 233 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase() 234 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}" 235 def email_body = """<p>This is an automated email from the Jenkins build machine. It was 236 generated because of a git hooks/post-receive script following 237 a ref change which was pushed to the C\u2200 repository.</p> 238 239 <p>- Status --------------------------------------------------------------</p> 240 241 <p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p> 242 <p>Check console output at ${env.BUILD_URL} to view the results.</p> 243 """ + Tools.GitLogMessage() 244 245 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca" 246 247 if( Settings && !Settings.Silent ) { 248 //send email notification 249 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log 250 } else { 251 echo "Would send email to: ${email_to}" 252 echo "With title: ${email_subject}" 253 echo "Content: \n${email_body}" 254 } 250 255 } 251 256 } -
doc/theses/andrew_beach_MMath/future.tex
r4aba055 r2f19e03 7 7 that I had to workaround while building an exception handling system largely in 8 8 the \CFA language (some C components). The following are a few of these 9 issues, and once implemented/fixed, how th iswould affect the exception system.9 issues, and once implemented/fixed, how they would affect the exception system. 10 10 \begin{itemize} 11 11 \item … … 13 13 hand-crafted assembly statements. These sections must be ported by hand to 14 14 support more hardware architectures, such as the ARM processor. 15 \PAB{I think this is a straw-man problem because the hand-coded assembler code 16 has to be generated somewhere, and that somewhere is hand-coded.} 15 17 \item 16 18 Due to a type-system problem, the catch clause cannot bind the exception to a 17 19 reference instead of a pointer. Since \CFA has a very general reference 18 20 capability, programmers will want to use it. Once fixed, this capability should 19 result in little or no change in the exception system .21 result in little or no change in the exception system but simplify usage. 20 22 \item 21 23 Termination handlers cannot use local control-flow transfers, \eg by @break@, … … 28 30 There is no detection of colliding unwinds. It is possible for clean-up code 29 31 run during an unwind to trigger another unwind that escapes the clean-up code 30 itself ; such asa termination exception caught further down the stack or a31 cancellation. There do exist ways to handle this but currently they are not32 even detected and the first unwind will simply be forgotten, often leaving33 it in a bad state. 32 itself, \eg, a termination exception caught further down the stack or a 33 cancellation. There do exist ways to handle this issue, but currently they are not 34 even detected and the first unwind is simply dropped, often leaving 35 it in a bad state. \Cpp terminates the program in this case, and Java picks the ... 34 36 \item 35 37 Also the exception system did not have a lot of time to be tried and tested. … … 41 43 The virtual system should be completed. It was not supposed to be part of this 42 44 project, but was thrust upon it to do exception inheritance; hence, only 43 minimal work was done. A draft for a complete virtual system is available but45 minimal work is done. A draft for a complete virtual system is available but 44 46 it is not finalized. A future \CFA project is to complete that work and then 45 47 update the exception system that uses the current version. … … 67 69 bad software engineering. 68 70 69 Non-local/concurrent r equires more coordination between the concurrency system71 Non-local/concurrent raise requires more coordination between the concurrency system 70 72 and the exception system. Many of the interesting design decisions centre 71 around masking (controlling which exceptions may be thrown at a stack). It73 around masking, \ie controlling which exceptions may be thrown at a stack. It 72 74 would likely require more of the virtual system and would also effect how 73 75 default handlers are set. … … 85 87 86 88 \section{Checked Exceptions} 87 Checked exceptions make exceptions part of a function's type by adding the89 Checked exceptions make exceptions part of a function's type by adding an 88 90 exception signature. An exception signature must declare all checked 89 exceptions that could prop ogate from the function (either because they were91 exceptions that could propagate from the function (either because they were 90 92 raised inside the function or came from a sub-function). This improves safety 91 93 by making sure every checked exception is either handled or consciously 92 94 passed on. 93 95 94 However checked exceptions were never seriously considered for this project 95 for two reasons. The first is due to time constraints, even copying an 96 existing checked exception system would be pushing the remaining time and 97 trying to address the second problem would take even longer. The second 98 problem is that checked exceptions have some real usability trade-offs in 96 However checked exceptions were never seriously considered for this project because 97 they have significant usability and reuse trade-offs in 99 98 exchange for the increased safety. 100 101 99 These trade-offs are most problematic when trying to pass exceptions through 102 100 higher-order functions from the functions the user passed into the 103 101 higher-order function. There are no well known solutions to this problem 104 that were s tatifactory for \CFA (which carries some of C's flexability105 over safety design) so one would have to be researched and developed.102 that were satisfactory for \CFA (which carries some of C's flexibility 103 over safety design) so additional research is needed. 106 104 107 Follow-up work might add checked exceptions to\CFA, possibly using108 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or105 Follow-up work might find a compromise design for checked exceptions in \CFA, possibly using 106 polymorphic exception signatures, a form of tunneling\cite{Zhang19}, or 109 107 checked and unchecked raises. 110 108 … … 150 148 For instance, resumption could be extended to cover this use by allowing local 151 149 control flow out of it. This approach would require an unwind as part of the 152 transition as there are stack frames that have to be removed . This approach153 means there is no notify raise, but because \CFA does not have exception154 signatures, a termination canbe thrown from within any resumption handler so155 there is already a way to do mimic this in existing \CFA.150 transition as there are stack frames that have to be removed back to the resumption handler. This approach 151 means no special statement is required in the handler to continue after it. 152 Currently, \CFA allows a termination exception to be thrown from within any resumption handler so 153 there is already a way to partially mimic signal exceptions. 156 154 157 155 % Maybe talk about the escape; and escape CONTROL_STMT; statements or how -
doc/theses/andrew_beach_MMath/implement.tex
r4aba055 r2f19e03 2 2 \label{c:implement} 3 3 4 The implementation work for this thesis covers t wo components: thevirtual4 The implementation work for this thesis covers the two components: virtual 5 5 system and exceptions. Each component is discussed in detail. 6 6 … … 17 17 pointer to the virtual table, which is called the \emph{virtual-table pointer}. 18 18 Internally, the field is called \snake{virtual_table}. 19 The field is fixed after construction . It is always the first field in the19 The field is fixed after construction and is the first field in the 20 20 structure so that its location is always known. 21 21 \todo{Talk about constructors for virtual types (after they are working).} 22 22 23 Th is is what binds an instance of a virtual type to avirtual table. This24 pointer can be used as an identity check. It can also be used to access the23 The virtual-table pointer is what binds an instance of a virtual type to its virtual table. This 24 pointer is used as an identity check, and to access the 25 25 virtual table and the virtual members there. 26 26 27 27 \subsection{Type Id} 28 28 Every virtual type has a unique id. 29 Type ids can be compared for equality ( the types reperented are the same)29 Type ids can be compared for equality (\ie the types represented are the same) 30 30 or used to access the type's type information. 31 31 The type information currently is only the parent's type id or, if the 32 type has no parent, zero.32 type has no parent, @0p@. 33 33 34 34 The id's are implemented as pointers to the type's type information instance. 35 Derefe ncing the pointer gets the type information.36 By going back-and-forth between the type id and 37 the type info one can find every ancestor of a virtual type.38 Italso pushes the issue of creating a unique value (for35 Dereferencing the pointer gets the type information. 36 The ancestors of a virtual type are found by traversing the type id through 37 the type information. 38 An id also pushes the issue of creating a unique value (for 39 39 the type id) to the problem of creating a unique instance (for type 40 information) which the linker can solve.40 information), which the linker can solve. 41 41 42 42 Advanced linker support is required because there is no place that appears 43 43 only once to attach the type information to. There should be one structure 44 definition but it is included in multiple translation units . Each virtual45 table definition should be unique but there are an arbitrary number of th oses.46 So the special section prefix \texttt{.gnu.linkonce} is used.47 With a unique suffix (making the entire section name unique) the linker will48 remove multiple definition making sureonly one version exists after linking.44 definition but it is included in multiple translation units because of separate compilation. Each virtual 45 table definition should be unique but there are an arbitrary number of these, 46 so the special section prefix \texttt{.gnu.linkonce} is used. 47 With a generated unique suffix (making the entire section name unique) the linker 48 removes multiple definition ensuring only one version exists after linking. 49 49 Then it is just a matter of making sure there is a unique name for each type. 50 50 51 This is done in three phases. 51 These steps are done in three phases. 52 \begin{enumerate} 53 \item 52 54 The first phase is to generate a new structure definition to store the type 53 55 information. The layout is the same in each case, just the parent's type id, … … 55 57 The structure's name is change, it is based off the virtual type's name, and 56 58 the type of the parent's type id. 57 If the virtual type is polymorphic then the type information structure is59 If the virtual type is polymorphic, then the type information structure is 58 60 polymorphic as well, with the same polymorphic arguments. 59 61 \item 60 62 The second phase is to generate an instance of the type information with a 61 63 almost unique name, generated by mangling the virtual type name. 62 64 \item 63 65 The third phase is implicit with \CFA's overloading scheme. \CFA mangles 64 66 names with type information so that all of the symbols exported to the linker 65 are unique even if in \CFA code they are the same. Having two declarations67 are unique even if in the \CFA code they are the same. Having two declarations 66 68 with the same name and same type is forbidden because it is impossible for 67 overload resolution to pick between them. This is why a unique type is69 overload resolution to pick between them. This is the reason why a unique type is 68 70 generated for each virtual type. 69 71 Polymorphic information is included in this mangling so polymorphic 70 types will have seperate instances for each set of polymorphic arguments. 71 72 types have separate instances for each set of polymorphic arguments. 73 \end{enumerate} 74 The following example shows the components for a generated virtual type. 72 75 \begin{cfa} 73 76 struct TYPE_ID_TYPE { … … 81 84 \end{cfa} 82 85 83 \subsubsection{ cfa\_linkonceAttribute}86 \subsubsection{\lstinline{cfa_linkonce} Attribute} 84 87 Another feature added to \CFA is a new attribute: \texttt{cfa\_linkonce}. 85 This attribute can be put onan object or function definition86 (any global declaration with a name and a type) .87 This allows you to define that object or functionmultiple times.88 All definitions should have the link-once attribute on them and allshould88 This attribute is attached to an object or function definition 89 (any global declaration with a name and a type) 90 allowing it to be defined multiple times. 91 All matching definitions must have the link-once attribute on them and should 89 92 be identical. 90 91 The simplist way to use it is to put a definition in a header where the 92 forward declaration would usually go. 93 This is how it is used for type-id instances. There was is no unique location 94 associated with a type except for the type definition which is in a header. 95 This allows the unique type-id object to be generated there. 96 97 Internally @cfa_linkonce@ removes all @section@ attributes 98 from the declaration (as well as itself) and replaces them with 93 This attributed prototype is placed in a header file with other 94 forward declaration. 95 96 This technique is used for type-id instances, as there is no unique location 97 associated with a type, except for the type definition in a header. 98 The result is the unique type-id object generated by the linker. 99 100 Internally, @cfa_linkonce@ is replaced with 99 101 @section(".gnu.linkonce.NAME")@ where \texttt{NAME} is replaced by the 100 102 mangled name of the object. 103 Any other @section@ attributes are also removed from the declaration. 101 104 The prefix \texttt{.gnu.linkonce} in section names is recognized by the 102 linker. If two of these sections with the same name, including everything103 that comes after the special prefix, then only one will beused and the other104 will bediscarded.105 linker. If two of these sections appear with the same name, including everything 106 that comes after the special prefix, then only one is used and the other 107 discarded. 105 108 106 109 \subsection{Virtual Table} … … 112 115 below. 113 116 114 The layout always comes in three parts. 117 Figure~\ref{f:VirtualTableLayout} shows the layout is in three parts. 118 \PAB{Number the parts in the figure.} 119 \begin{enumerate} 120 \item 115 121 The first section is just the type id at the head of the table. It is always 116 there to ensure that 122 there to ensure that \PAB{... missing text to end this sentence} 123 \item 117 124 The second section are all the virtual members of the parent, in the same 118 125 order as they appear in the parent's virtual table. Note that the type may 119 change slightly as references to the ``this" will change. Thisis limited to126 change slightly as references to the @this@ change. This structure is limited to 120 127 inside pointers/references and via function pointers so that the size (and 121 128 hence the offsets) are the same. 129 \item 122 130 The third section is similar to the second except that it is the new virtual 123 131 members introduced at this level in the hierarchy. 132 \end{enumerate} 124 133 125 134 \begin{figure} … … 133 142 prefix that has the same layout and types as its parent virtual table. 134 143 This, combined with the fixed offset to the virtual table pointer, means that 135 for any virtual type it doesn't matter if we haveit or any of its136 descendants , it is still always safe to access the virtual tablethrough144 for any virtual type, it or any of its 145 descendants can be accessed through 137 146 the virtual table pointer. 138 From there it is safe to check the type id to identify the exact type of the139 underlying object, access any of the virtual members and pass the object to147 From there, it is safe to check the type id to identify the exact type of the 148 underlying object, access any of the virtual members, and pass the object to 140 149 any of the method-like virtual members. 141 150 142 When a virtual table is declared the user decides where to declare it and its151 When a virtual table is declared, the user decides where to declare it and its 143 152 name. The initialization of the virtual table is entirely automatic based on 144 153 the context of the declaration. 145 154 146 The type id is always fixed , each virtual table type will always have one155 The type id is always fixed with each virtual table type having 147 156 exactly one possible type id. 148 The virtual members are usually filled in byresolution. The best match for149 a given name and type at the declaration site is filled in.157 The virtual members are usually filled in during type resolution. The best match for 158 a given name and type at the declaration site is used. 150 159 There are two exceptions to that rule: the @size@ field is the type's size 151 and is set to the result of a @sizeof@ expression,the @align@ field is the152 type's alignment and similarly usesan @alignof@ expression.160 set using a @sizeof@ expression, and the @align@ field is the 161 type's alignment set using an @alignof@ expression. 153 162 154 163 \subsubsection{Concurrency Integration} 155 164 Coroutines and threads need instances of @CoroutineCancelled@ and 156 165 @ThreadCancelled@ respectively to use all of their functionality. When a new 157 data type is declared with @coroutine@ or @thread@ theforward declaration for166 data type is declared with @coroutine@ or @thread@, a forward declaration for 158 167 the instance is created as well. The definition of the virtual table is created 159 168 at the definition of the main function. 169 170 Figure~\ref{f:ConcurrencyTransformations} shows ... 171 \todo{Improve Concurrency Transformations figure.} 160 172 161 173 \begin{figure} … … 194 206 \label{f:ConcurrencyTransformations} 195 207 \end{figure} 196 \todo{Improve Concurrency Transformations figure.}197 208 198 209 \subsection{Virtual Cast} … … 211 222 the cast target is passed in as @child@. 212 223 213 For C generation both arguments and the result are wrappedwith type casts.214 There is also an internal storeinside the compiler to make sure that the224 The generated C code wraps both arguments and the result with type casts. 225 There is also an internal check inside the compiler to make sure that the 215 226 target type is a virtual type. 216 227 % It also checks for conflicting definitions. 217 228 218 The virtual cast either returns the original pointer as a new type or null.219 So the function just does the parent check and returns the appropr ate value.229 The virtual cast either returns the original pointer as a new type or 0p. 230 So the function just does the parent check and returns the appropriate value. 220 231 The parent check is a simple linear search of child's ancestors using the 221 232 type information. … … 229 240 % resumption doesn't as well. 230 241 231 % Many modern languages work with an inter al stack that function push and pop242 % Many modern languages work with an internal stack that function push and pop 232 243 % their local data to. Stack unwinding removes large sections of the stack, 233 244 % often across functions. … … 236 247 stack. On function entry and return, unwinding is handled directly by the 237 248 call/return code embedded in the function. 238 In many cases the position of the instruction pointer (relative to parameter249 In many cases, the position of the instruction pointer (relative to parameter 239 250 and local declarations) is enough to know the current size of the stack 240 251 frame. 241 252 242 253 Usually, the stack-frame size is known statically based on parameter and 243 local variable declarations. Even with dynamic stack-size the information244 to determ ainhow much of the stack has to be removed is still contained254 local variable declarations. Even with dynamic stack-size, the information 255 to determine how much of the stack has to be removed is still contained 245 256 within the function. 246 257 Allocating/deallocating stack space is usually an $O(1)$ operation achieved by 247 258 bumping the hardware stack-pointer up or down as needed. 248 Constructing/destructing values on the stack takes longer put in terms of 249 figuring out what needs to be done is of similar complexity. 259 In fact, constructing/destructing values within a stack frame is of similar complexity but often takes longer. 250 260 251 261 Unwinding across multiple stack frames is more complex because that 252 262 information is no longer contained within the current function. 253 With sep erate compilation a function has no way of knowing what its callers254 are so it can't know how large those frames are.255 Without altering the main code path it is also hard to pass that work off263 With separate compilation a function has no way of knowing what its callers 264 so it can not know how large those frames are. 265 Without altering the main code path, it is also hard to pass that work off 256 266 to the caller. 257 267 … … 261 271 reseting to a snap-shot of an arbitrary but existing function frame on the 262 272 stack. It is up to the programmer to ensure the snap-shot is valid when it is 263 reset and that all required clean-up from the unwound stacks is p reformed.264 This approach is fragile and forces a work onto the surounding code.265 266 With respect to th at work forced onto the surounding code,273 reset and that all required clean-up from the unwound stacks is performed. 274 This approach is fragile and forces extra work in the surrounding code. 275 276 With respect to the extra work in the surrounding code, 267 277 many languages define clean-up actions that must be taken when certain 268 278 sections of the stack are removed. Such as when the storage for a variable 269 is removed from the stack or when a trystatement with a finally clause is279 is removed from the stack or when a @try@ statement with a finally clause is 270 280 (conceptually) popped from the stack. 271 None of these should be handled by the user,that would contradict the272 intention of these features ,so they need to be handled automatically.273 274 To safely remove sections of the stack the language must be able to find and281 None of these should be handled explicitly by the user --- that would contradict the 282 intention of these features --- so they need to be handled automatically. 283 284 To safely remove sections of the stack, the language must be able to find and 275 285 run these clean-up actions even when removing multiple functions unknown at 276 286 the beginning of the unwinding. … … 294 304 current stack frame, and what handlers should be checked. Theoretically, the 295 305 LSDA can contain any information but conventionally it is a table with entries 296 representing regions of thefunction and what has to be done there during306 representing regions of a function and what has to be done there during 297 307 unwinding. These regions are bracketed by instruction addresses. If the 298 308 instruction pointer is within a region's start/end, then execution is currently 299 309 executing in that region. Regions are used to mark out the scopes of objects 300 with destructors and tryblocks.310 with destructors and @try@ blocks. 301 311 302 312 % Libunwind actually does very little, it simply moves down the stack from … … 314 324 int avar __attribute__(( cleanup(clean_up) )); 315 325 \end{cfa} 316 The attribu e is used on a variable and specifies a function,326 The attribute is used on a variable and specifies a function, 317 327 in this case @clean_up@, run when the variable goes out of scope. 318 This is enough to mimic destructors, but not trystatements which can effect328 This capability is enough to mimic destructors, but not @try@ statements which can effect 319 329 the unwinding. 320 330 321 To get full unwinding support all of this has to bedone directly with322 assembly and assembler directives . Partiularly the cfi directives323 \snake{.cfi_ lsda} and \snake{.cfi_personality}.331 To get full unwinding support, all of these components must done directly with 332 assembly and assembler directives, particularly the cfi directives 333 \snake{.cfi_Leda} and \snake{.cfi_personality}. 324 334 325 335 \subsection{Personality Functions} … … 327 337 section covers some of the important parts of the interface. 328 338 329 A personality function can p reform different actions depending on how it is339 A personality function can perform different actions depending on how it is 330 340 called. 331 341 \begin{lstlisting} … … 364 374 365 375 The @exception_class@ argument is a copy of the 366 \code{C}{exception}'s @exception_class@ field .367 This a number that identifies the exception handling mechanism that created368 the 369 370 The \code{C}{exception} argument is a pointer to theuser376 \code{C}{exception}'s @exception_class@ field, 377 which is a number that identifies the exception handling mechanism that created 378 the \PAB{... missing text to end this sentence} 379 380 The \code{C}{exception} argument is a pointer to a user 371 381 provided storage object. It has two public fields: the @exception_class@, 372 382 which is described above, and the @exception_cleanup@ function. 373 The clean-up function is used by the EHM to clean-up the exception if it383 The clean-up function is used by the EHM to clean-up the exception, if it 374 384 should need to be freed at an unusual time, it takes an argument that says 375 385 why it had to be cleaned up. … … 382 392 messages for special cases (some of which should never be used by the 383 393 personality function) and error codes. However, unless otherwise noted, the 384 personality function shouldalways return @_URC_CONTINUE_UNWIND@.394 personality function always return @_URC_CONTINUE_UNWIND@. 385 395 386 396 \subsection{Raise Exception} 387 Raising an exception is the central function of libunwind and it performs a397 Raising an exception is the central function of libunwind and it performs the 388 398 two-staged unwinding. 389 399 \begin{cfa} … … 472 482 % catches. Talk about GCC nested functions. 473 483 474 \CFA termination exceptions use libunwind heavily because they match \Cpp484 \CFA termination exceptions use libunwind heavily because they match 475 485 \Cpp exceptions closely. The main complication for \CFA is that the 476 486 compiler generates C code, making it very difficult to generate the assembly to 477 form the LSDA for tryblocks or destructors.487 form the LSDA for @try@ blocks or destructors. 478 488 479 489 \subsection{Memory Management} … … 485 495 486 496 \begin{figure} 497 \centering 487 498 \input{exception-layout} 488 499 \caption{Exception Layout} … … 491 502 \todo*{Convert the exception layout to an actual diagram.} 492 503 493 Exceptions are stored in variable-sized blocks (see \vref{f:ExceptionLayout}).504 Exceptions are stored in variable-sized blocks (see Figure~\vref{f:ExceptionLayout}). 494 505 The first component is a fixed-sized data structure that contains the 495 506 information for libunwind and the exception system. The second component is an … … 498 509 @_Unwind_Exception@ to the entire node. 499 510 500 Multip e exceptions can exist at the same time because exceptions can be511 Multiple exceptions can exist at the same time because exceptions can be 501 512 raised inside handlers, destructors and finally blocks. 502 513 Figure~\vref{f:MultipleExceptions} shows a program that has multiple 503 514 exceptions active at one time. 504 515 Each time an exception is thrown and caught the stack unwinds and the finally 505 clause runs. This will throwanother exception (until @num_exceptions@ gets506 high enough) which must be allocated. The previous exceptions may not be516 clause runs. This handler throws another exception (until @num_exceptions@ gets 517 high enough), which must be allocated. The previous exceptions may not be 507 518 freed because the handler/catch clause has not been run. 508 So the EHM must keep themalive while it allocates exceptions for new throws.519 Therefore, the EHM must keep all of these exceptions alive while it allocates exceptions for new throws. 509 520 510 521 \begin{figure} … … 559 570 \todo*{Work on multiple exceptions code sample.} 560 571 561 All exceptions are stored in nodes which are then linked together in lists,572 All exceptions are stored in nodes, which are then linked together in lists 562 573 one list per stack, with the 563 574 list head stored in the exception context. Within each linked list, the most … … 566 577 exception is being handled. The exception at the head of the list is currently 567 578 being handled, while other exceptions wait for the exceptions before them to be 568 removed.579 handled and removed. 569 580 570 581 The virtual members in the exception's virtual table provide the size of the … … 573 584 exception into managed memory. After the exception is handled, the free 574 585 function is used to clean up the exception and then the entire node is 575 passed to free so the memory can be given backto the heap.586 passed to free so the memory is returned to the heap. 576 587 577 588 \subsection{Try Statements and Catch Clauses} 578 The trystatement with termination handlers is complex because it must579 compensate for the lack of assembly-code generatedfrom \CFA. Libunwind589 The @try@ statement with termination handlers is complex because it must 590 compensate for the C code-generation versus assembly-code generation from \CFA. Libunwind 580 591 requires an LSDA and personality function for control to unwind across a 581 592 function. The LSDA in particular is hard to mimic in generated C code. 582 593 583 594 The workaround is a function called @__cfaehm_try_terminate@ in the standard 584 library. The contents of a tryblock and the termination handlers are converted595 library. The contents of a @try@ block and the termination handlers are converted 585 596 into functions. These are then passed to the try terminate function and it 586 597 calls them. 587 598 Because this function is known and fixed (and not an arbitrary function that 588 happens to contain a trystatement), the LSDA can be generated ahead599 happens to contain a @try@ statement), the LSDA can be generated ahead 589 600 of time. 590 601 … … 592 603 embedded assembly. This assembly code is handcrafted using C @asm@ statements 593 604 and contains 594 enough information for the single try statement the function repersents.605 enough information for a single @try@ statement the function represents. 595 606 596 607 The three functions passed to try terminate are: 597 608 \begin{description} 598 \item[try function:] This function is the try block,all the code inside the599 try block is placed inside the tryfunction. It takes no parameters and has no609 \item[try function:] This function is the @try@ block, where all the code inside the 610 @try@ block is wrapped inside the function. It takes no parameters and has no 600 611 return value. This function is called during regular execution to run the try 601 612 block. … … 609 620 handler that matches the exception. 610 621 611 \item[handler function:] This function handles the exception. It takes a 622 \item[handler function:] This function handles the exception, where the code inside 623 is constructed by stitching together the bodies of 624 each handler of a @try@ statement and dispatches to the selected handler. 625 It takes a 612 626 pointer to the exception and the handler's id and returns nothing. It is called 613 after the cleanup phase. It is constructed by stitching together the bodies of 614 each handler and dispatches to the selected handler. 627 after the cleanup phase. 615 628 \end{description} 616 629 All three functions are created with GCC nested functions. GCC nested functions 617 can be used to create closures, functions that can refer to the state of other630 can be used to create closures, \ie functions that can refer to the state of other 618 631 functions on the stack. This approach allows the functions to refer to all the 619 632 variables in scope for the function containing the @try@ statement. These … … 623 636 Using this pattern, \CFA implements destructors with the cleanup attribute. 624 637 638 Figure~\ref{f:TerminationTransformation} shows an example transformation for a \CFA @try@ 639 statement with @catch@ clauses into corresponding C functions. \PAB{Walk the reader through the example code.} 640 625 641 \begin{figure} 626 642 \begin{cfa} … … 633 649 } 634 650 \end{cfa} 651 652 \medskip 653 \hrule 654 \medskip 635 655 636 656 \begin{cfa} … … 683 703 % The stack-local data, the linked list of nodes. 684 704 685 Resumption simpler to implement than termination705 Resumption is simpler to implement than termination 686 706 because there is no stack unwinding. 687 707 Instead of storing the data in a special area using assembly, 688 708 there is just a linked list of possible handlers for each stack, 689 with each node on the list reperenting a trystatement on the stack.709 with each list node representing a @try@ statement on the stack. 690 710 691 711 The head of the list is stored in the exception context. 692 The nodes are stored in order, with the more recent trystatements closer712 The nodes are stored in order, with the more recent @try@ statements closer 693 713 to the head of the list. 694 Instead of traversing the stack resumption handling traverses the list.695 At each node the EHM checks to see if the try statement the node repersents714 Instead of traversing the stack, resumption handling traverses the list. 715 At each node, the EHM checks to see if the @try@ statement it represents 696 716 can handle the exception. If it can, then the exception is handled and 697 717 the operation finishes, otherwise the search continues to the next node. 698 If the search reaches the end of the list without finding a trystatement699 that can handle the exception the default handler is executed and the718 If the search reaches the end of the list without finding a @try@ statement 719 that can handle the exception, the default handler is executed and the 700 720 operation finishes. 701 721 702 In each node is a handler function which does most of the work there. 703 The handler function is passed the raised the exception and returns true 704 if the exception is handled and false if it cannot be handled here. 705 706 For each @catchResume@ clause the handler function will: 707 check to see if the raised exception is a descendant type of the declared 708 exception type, if it is and there is a conditional expression then it will 709 run the test, if both checks pass the handling code for the clause is run 710 and the function returns true, otherwise it moves onto the next clause. 722 Each node has a handler function that does most of the work. 723 The handler function is passed the raised exception and returns true 724 if the exception is handled and false otherwise. 725 726 For each @catchResume@ clause, the handler function: 727 \begin{itemize} 728 \item 729 checks to see if the raised exception is a descendant type of the declared 730 exception type, 731 \item 732 if it is and there is a conditional expression then it 733 runs the test, 734 \item 735 if both checks pass the handling code for the clause is run and the function returns true, 736 \item 737 otherwise it moves onto the next clause. 738 \end{itemize} 711 739 If this is the last @catchResume@ clause then instead of moving onto 712 740 the next clause the function returns false as no handler could be found. 741 742 Figure~\ref{f:ResumptionTransformation} shows an example transformation for a \CFA @try@ 743 statement with @catchResume@ clauses into corresponding C functions. \PAB{Walk the reader through the example code.} 713 744 714 745 \begin{figure} … … 753 784 754 785 % Recursive Resumption Stuff: 755 Search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of786 Figure~\ref{f:ResumptionMarking} shows the search skipping (see \vpageref{s:ResumptionMarking}), which ignores parts of 756 787 the stack 757 788 already examined, is accomplished by updating the front of the list as the … … 759 790 is updated to the next node of the current node. After the search is complete, 760 791 successful or not, the head of the list is reset. 761 762 792 This mechanism means the current handler and every handler that has already 763 793 been checked are not on the list while a handler is run. If a resumption is 764 thrown during the handling of another resumption the active handlers and all794 thrown during the handling of another resumption, the active handlers and all 765 795 the other handler checked up to this point are not checked again. 766 767 This structure also supports new handler added while the resumption is being 796 This structure also supports new handlers added while the resumption is being 768 797 handled. These are added to the front of the list, pointing back along the 769 798 stack -- the first one points over all the checked handlers -- and the ordering 770 799 is maintained. 800 \PAB{Maybe number the figure and use the numbers in the description to help the reader follow.} 771 801 772 802 \begin{figure} … … 778 808 779 809 \label{p:zero-cost} 780 Note, the resumption implementation has a cost for entering/exiting a @try@810 Finally, the resumption implementation has a cost for entering/exiting a @try@ 781 811 statement with @catchResume@ clauses, whereas a @try@ statement with @catch@ 782 812 clauses has zero-cost entry/exit. While resumption does not need the stack … … 798 828 around the context of the associated @try@ statement. 799 829 800 The rest is handled by GCC. The tryblock and all handlers are inside this830 The rest is handled by GCC. The @try@ block and all handlers are inside this 801 831 block. At completion, control exits the block and the empty object is cleaned 802 832 up, which runs the function that contains the finally code. … … 812 842 coroutine or thread. Fortunately, the thread library stores the main thread 813 843 pointer and the current thread pointer, and every thread stores a pointer to 814 its main coroutine and the coroutine it is currently executing. 815 \todo*{Consider adding a description of how threads are coroutines.} 816 817 If a the current thread's main and current coroutines are the same then the 818 current stack is a thread stack. Furthermore it is easy to compare the 819 current thread to the main thread to see if they are the same. And if this 820 is not a thread stack then it must be a coroutine stack. 844 its coroutine and the coroutine it is currently executing. 845 If the current thread's main and current coroutines are the same then the 846 current stack is a thread stack, otherwise it is a coroutine stack. 847 Note, the runtime considers a thread as a coroutine with an associated user-level thread; 848 hence, for many operations a thread and coroutine are treated uniformly. 849 %\todo*{Consider adding a description of how threads are coroutines.} 850 851 % Furthermore it is easy to compare the 852 % current thread to the main thread to see if they are the same. And if this 853 % is not a thread stack then it must be a coroutine stack. 821 854 822 855 However, if the threading library is not linked, the sequential execution is on 823 856 the main stack. Hence, the entire check is skipped because the weak-symbol 824 function is loaded. Therefore, amain thread cancellation is unconditionally857 function is loaded. Therefore, main thread cancellation is unconditionally 825 858 performed. 826 859 827 860 Regardless of how the stack is chosen, the stop function and parameter are 828 861 passed to the forced-unwind function. The general pattern of all three stop 829 functions is the same: theycontinue unwinding until the end of stack and830 then p reform theirtransfer.862 functions is the same: continue unwinding until the end of stack and 863 then perform the appropriate transfer. 831 864 832 865 For main stack cancellation, the transfer is just a program abort. … … 834 867 For coroutine cancellation, the exception is stored on the coroutine's stack, 835 868 and the coroutine context switches to its last resumer. The rest is handled on 836 the backside of the resume, which check if the resumed coroutine is869 the backside of the resume, which checks if the resumed coroutine is 837 870 cancelled. If cancelled, the exception is retrieved from the resumed coroutine, 838 871 and a @CoroutineCancelled@ exception is constructed and loaded with the 839 872 cancelled exception. It is then resumed as a regular exception with the default 840 873 handler coming from the context of the resumption call. 874 This semantics allows a cancellation to cascade through an arbitrary set of resumed 875 coroutines back to the thread's coroutine, performing cleanup along the way. 841 876 842 877 For thread cancellation, the exception is stored on the thread's main stack and … … 848 883 null (as it is for the auto-generated joins on destructor call), the default is 849 884 used, which is a program abort. 885 This semantics allows a cancellation to cascade through an arbitrary set of joining 886 threads back to the program's main, performing cleanup along the way. 850 887 %; which gives the required handling on implicate join. -
doc/theses/andrew_beach_MMath/performance.tex
r4aba055 r2f19e03 6 6 7 7 Performance has been of secondary importance for most of this project. 8 The driving for has been to get the features working, the only performance 9 requirements were to make sure the tests for correctness rain in a reasonable 8 Instead, the goal has been to get the features working. 9 The only performance 10 requirements is to ensure the exception tests for correctness ran in a reasonable 10 11 amount of time. 11 Still this is an implementation others could use for similar prototypes and 12 so the results still have some use. 12 Much of the implementation is still reasonable and could be used for similar prototypes. 13 Hence, 14 the work still has some use. 15 To get a rough idea about the \CFA implementation, tests are run on \CFA, C++ and Java, which have similar termination-handling exceptions. 16 Tests are also run on \CFA and uC++, which has similar resumption-handling exceptions. 13 17 14 \section{Test Set-Up} 15 Tests will be run on \CFA, C++ and Java. 16 18 \section{Termination Comparison} 17 19 C++ is the most comparable language because both it and \CFA use the same 18 20 framework, libunwind. 19 In fact the comparison is almost entirely a quality of implementation21 In fact, the comparison is almost entirely a quality of implementation 20 22 comparison. \CFA's EHM has had significantly less time to be optimized and 21 23 does not generate its own assembly. It does have a slight advantage in that 22 24 there are some features it does not handle. 23 25 24 % Some languages I left out: 25 % Python: Its a scripting language, different 26 % uC++: Not well known and should the same results as C++, except for 27 % resumption which should be the same. 28 \todo{Can we find a good language to compare resumptions in.} 26 The Java comparison is an opportunity to compare a managed memory model with unmanaged, 27 to see if there are any effects related to the exception model. 29 28 30 All tests will be run inside a main loop which will perform the test 31 repeatedly. This is to avoid letting and start-up or tear-down time from 29 \subsection{Test Set-Up} 30 All tests are run inside a main loop that performs the test 31 repeatedly. This design avoids start-up or tear-down time from 32 32 affecting the timing results. 33 This also means that tests cannot terminate the program, which does limit33 A consequence is that tests cannot terminate the program, which does limit 34 34 how tests can be implemented. There are catch-alls to keep unhandled 35 exceptions from terminating t he program.35 exceptions from terminating tests. 36 36 37 The exceptions used in this test will always bea new exception based off of38 the base exception. This should minimize and preformance differences based37 The exceptions used in this test are always a new exception based off of 38 the base exception. This requirement minimizes performance differences based 39 39 on the object model. 40 Catch-alls will be done by catching the root exception type (not using \Cpp's40 Catch-alls are done by catching the root exception type (not using \Cpp's 41 41 \code{C++}{catch(...)}). 42 42 … … 44 44 hot. 45 45 46 \section{Tests} 46 \subsection{Tests} 47 The following tests capture the most important aspects of exception handling and should provide 48 a reasonable guide to programmers of where EHM costs occur. 49 47 50 \paragraph{Raise/Handle} 48 51 What is the basic cost to raise and handle an exception? 49 52 50 There are a number of factors that can effect this, for \CFA this includes 53 There are a number of factors that can effect this. 54 For \CFA this includes 51 55 the type of raise, 52 56 … … 61 65 This has the same set-up as the raise/handle test except the intermediate 62 66 stack frames contain either an object declaration with a destructor or a 63 try statement with no handlers except for a finallyclause.67 @try@ statement with no handlers except and a @finally@ clause. 64 68 65 69 \paragraph{Enter/Leave} … … 67 71 is thrown? 68 72 69 Th is is the simplist pattern to test as it is a simple matter of entering73 The test is a simple matter of entering 70 74 and leaving a try statement. 71 75 … … 74 78 75 79 \paragraph{Re-throw and Conditional-Catch} 76 How expen cive it is to run a non-exception type check for a handler?80 How expensive it is to run a non-exception type check for a handler? 77 81 78 82 In this case different languages approach this problem differently, either 79 83 through a re-throw or a conditional-catch. 80 Where \CFA uses its condition other languages will have tounconditionally84 Where \CFA uses its condition, other languages must unconditionally 81 85 catch the exception then re-throw if the condition if the condition is false. 82 86 … … 86 90 % We could do a Cforall test without the catch all and a new default handler 87 91 % that does a catch all. 88 As a point of comparison one of the raise/handle tests (which one?) has92 As a point of comparison, one of the raise/handle tests (which one?) has 89 93 same layout but never catches anything. 90 94 … … 100 104 %(I haven't actually figured out how to compare this, probably using something 101 105 %related to -fexceptions.) 106 107 108 \section{Resumption Comparison} 109 % Some languages I left out: 110 % Python: Its a scripting language, different 111 % uC++: Not well known and should the same results as C++, except for 112 % resumption which should be the same. 113 \todo{Can we find a good language to compare resumptions in.} -
doc/theses/mubeen_zulfiqar_MMath/benchmarks.tex
r4aba055 r2f19e03 34 34 \noindent 35 35 ==================== 36 37 \section Performance Matrices of Memory Allocators 38 39 When it comes to memory allocators, there are no set standards of performance. Performance of a memory allocator depends highly on the usage pattern of the application. A memory allocator that is the best performer for a certain application X might be the worst for some other application which has completely different memory usage pattern compared to the application X. It is extremely difficult to make one universally best memory allocator which will outperform every other memory allocator for every usage pattern. So, there is a lack of a set of standard benchmarks that are used to evaluate a memory allocators's performance. 40 41 If we breakdown the goals of a memory allocator, there are two basic matrices on which a memory allocator's performance is evaluated. 42 43 1. Memory Overhead 44 2. Speed 45 46 /subsection Memory Overhead 47 Memory overhead is the extra memory that a memory allocator takes from OS which is not requested by the application. Ideally, an allocator should get just enough memory from OS that can fulfill application's request and should return this memory to OS as soon as applications frees it. But, allocators retain more memory compared to what application has asked for which causes memory overhead. Memory overhead can happen for various reasons. 48 49 /subsubsection Fragmentation 50 Fragmentation is one of the major reasons behind memory overhead. Fragmentation happens because of situations that are either necassary for proper functioning of the allocator such as internal memory management and book-keeping or are out of allocator's control such as application's usage pattern. 51 52 /subsubsubsection Internal Fragmentation 53 For internal book-keeping, allocators divide raw memory given by OS into chunks, blocks, or lists that can fulfill application's requested size. Allocators use memory given by OS for creating headers, footers etc. to store information about these chunks, blocks, or lists. This increases usage of memory in-addition to the memory requested by application as the allocators need to store their book-keeping information. This extra usage of memory for allocator's own book-keeping is called Internal Fragmentation. Although it cases memory overhead but this overhead is necassary for an allocator's proper funtioning. 54 55 56 *** FIX ME: Insert a figure of internal fragmentation with explanation 57 58 /subsubsubsection External Fragmentation 59 External fragmentation is the free bits of memory between or around chunks of memory that are currently in-use of the application. Segmentation in memory due to application's usage pattern causes external fragmentation. The memory which is part of external fragmentation is completely free as it is neither used by allocator's internal book-keeping nor by the application. Ideally, an allocator should return a segment of memory back to the OS as soon as application frees it. But, this is not always the case. Allocators get memory from OS in one of the two ways. 60 61 \begin{itemize} 62 \item 63 MMap: an allocator can ask OS for whole pages in mmap area. Then, the allocator segments the page internally and fulfills application's request. 64 \item 65 Heap: an allocator can ask OS for memory in heap area using system calls such as sbrk. Heap are grows downwards and shrinks upwards. 66 \begin{itemize} 67 68 If an allocator uses mmap area, it can only return extra memory back to OS if the whole page is free i.e. no chunk on the page is in-use of the application. Even if one chunk on the whole page is currently in-use of the application, the allocator has to retain the whole page. 69 70 If an allocator uses the heap area, it can only return the continous free memory at the end of the heap area that is currently in allocator's possession as heap area shrinks upwards. If there are free bits of memory in-between chunks of memory that are currently in-use of the application, the allocator can not return these free bits. 71 72 *** FIX ME: Insert a figure of above scenrio with explanation 73 74 Even if the entire heap area is free except one small chunk at the end of heap area that is being used by the application, the allocator cannot return the free heap area back to the OS as it is not a continous region at the end of heap area. 75 76 *** FIX ME: Insert a figure of above scenrio with explanation 77 78 Such scenerios cause external fragmentation but it is out of the allocator's control and depend on application's usage pattern. 79 80 /subsubsection Internal Memory Management 81 Allocators such as je-malloc (FIX ME: insert reference) pro-actively get some memory from the OS and divide it into chunks of certain sizes that can be used in-future to fulfill application's request. This causes memory overhead as these chunks are made before application's request. There is also the possibility that an application may not even request memory of these sizes during their whole life-time. 82 83 *** FIX ME: Insert a figure of above scenrio with explanation 84 85 Allocators such as rp-malloc (FIX ME: insert reference) maintain lists or blocks of sized memory segments that is freed by the application for future use. These lists are maintained without any guarantee that application will even request these sizes again. 86 87 Such tactics are usually used to gain speed as allocator will not have to get raw memory from OS and manage it at the time of application's request but they do cause memory overhead. 88 89 Fragmentation and managed sized chunks of free memory can lead to Heap Blowup as the allocator may not be able to use the fragments or sized free chunks of free memory to fulfill application's requests of other sizes. 90 91 /subsection Speed 92 When it comes to performance evaluation of any piece of software, its runtime is usually the first thing that is evaluated. The same is true for memory allocators but, in case of memory allocators, speed does not only mean the runtime of memory allocator's routines but there are other factors too. 93 94 /subsubsection Runtime Speed 95 Low runtime is the main goal of a memory allocator when it comes it proving its speed. Runtime is the time that it takes for a routine of memory allocator to complete its execution. As mentioned in (FIX ME: refernce to routines' list), there four basic routines that are used in memory allocation. Ideally, each routine of a memory allocator should be fast. Some memory allocator designs use pro-active measures (FIX ME: local refernce) to gain speed when allocating some memory to the application. Some memory allocators do memory allocation faster than memory freeing (FIX ME: graph refernce) while others show similar speed whether memory is allocated or freed. 96 97 /subsubsection Memory Access Speed 98 Runtime speed is not the only speed matrix in memory allocators. The memory that a memory allocator has allocated to the application also needs to be accessible as quick as possible. The application should be able to read/write allocated memory quickly. The allocation method of a memory allocator may introduce some delays when it comes to memory access speed, which is specially important in concurrent applications. Ideally, a memory allocator should allocate all memory on a cache-line to only one thread and no cache-line should be shared among multiple threads. If a memory allocator allocates memory to multple threads on a same cache line, then cache may get invalidated more frequesntly when two different threads running on two different processes will try to read/write the same memory region. On the other hand, if one cache-line is used by only one thread then the cache may get invalidated less frequently. This sharing of one cache-line among multiple threads is called false sharing (FIX ME: cite wasik). 99 100 /subsubsubsection Active False Sharing 101 Active false sharing is the sharing of one cache-line among multiple threads that is caused by memory allocator. It happens when two threads request memory from memory allocator and the allocator allocates memory to both of them on the same cache-line. After that, if the threads are running on different processes who have their own caches and both threads start reading/writing the allocated memory simultanously, their caches will start getting invalidated every time the other thread writes something to the memory. This will cause the application to slow down as the process has to load cache much more frequently. 102 103 *** FIX ME: Insert a figure of above scenrio with explanation 104 105 /subsubsubsection Passive False Sharing 106 Passive false sharing is the kind of false sharing which is caused by the application and not the memory allocator. The memory allocator may preservce passive false sharing in future instead of eradicating it. But, passive false sharing is initiated by the application. 107 108 /subsubsubsubsection Program Induced Passive False Sharing 109 Program induced false sharing is completely out of memory allocator's control and is purely caused by the application. When a thread in the application creates multiple objects in the dynamic area and allocator allocates memory for these objects on the same cache-line as the objects are created by the same thread. Passive false sharing will occur if this thread passes one of these objects to another thread but it retains the rest of these objects or it passes some/all of the remaining objects to some third thread(s). Now, one cache-line is shared among multiple threads but it is caused by the application and not the allocator. It is out of allocator's control and has the similar performance impact as Active False Sharing (FIX ME: cite local) if these threads, who are sharing the same cache-line, start reading/writing the given objects simultanously. 110 111 *** FIX ME: Insert a figure of above scenrio 1 with explanation 112 113 *** FIX ME: Insert a figure of above scenrio 2 with explanation 114 115 /subsubsubsubsection Program Induced Allocator Preserved Passive False Sharing 116 Program induced allocator preserved passive false sharing is another interesting case of passive false sharing. Both the application and the allocator are partially responsible for it. It starts the same as Program Induced False Sharing (FIX ME: cite local). Once, an application thread has created multiple dynamic objects on the same cache-line and ditributed these objects among multiple threads causing sharing of one cache-line among multiple threads (Program Induced Passive False Sharing). This kind of false sharing occurs when one of these threads, which got the object on the shared cache-line, frees the passed object then re-allocates another object but the allocator returns the same object (on the shared cache-line) that this thread just freed. Although, the application caused the false sharing to happen in the frst place however, to prevent furthur false sharing, the allocator should have returned the new object on some other cache-line which is only shared by the allocating thread. When it comes to performnce impact, this passive false sharing will slow down the application just like any other kind of false sharing if the threads sharing the cache-line start reading/writing the objects simultanously. 117 118 *** FIX ME: Insert a figure of above scenrio with explanation -
libcfa/configure.ac
r4aba055 r2f19e03 131 131 #io_uring 5.5 uses enum values 132 132 #io_uring 5.6 and later uses probes 133 134 AH_TEMPLATE([CFA_HAVE_LINUX_RSEQ_H],[Defined if rseq support is present when compiling libcfathread.]) 135 AC_CHECK_HEADERS([linux/rseq.h], [AC_DEFINE(CFA_HAVE_LINUX_RSEQ_H)]) 136 137 AH_TEMPLATE([CFA_HAVE_LINUX_LIBRSEQ],[Defined if librseq support is present when compiling libcfathread.]) 138 AC_CHECK_LIB([rseq], [rseq_available], [AC_DEFINE(CFA_HAVE_LINUX_RSEQ_H)], []) 133 139 134 140 AH_TEMPLATE([CFA_HAVE_LINUX_IO_URING_H],[Defined if io_uring support is present when compiling libcfathread.]) -
libcfa/src/Makefile.am
r4aba055 r2f19e03 69 69 common.hfa \ 70 70 fstream.hfa \ 71 strstream.hfa \72 71 heap.hfa \ 73 72 iostream.hfa \ … … 78 77 rational.hfa \ 79 78 stdlib.hfa \ 79 strstream.hfa \ 80 80 time.hfa \ 81 81 bits/weakso_locks.hfa \ … … 83 83 containers/pair.hfa \ 84 84 containers/result.hfa \ 85 containers/vector.hfa 85 containers/vector.hfa \ 86 device/cpu.hfa 86 87 87 88 libsrc = ${inst_headers_src} ${inst_headers_src:.hfa=.cfa} \ -
libcfa/src/concurrency/kernel.cfa
r4aba055 r2f19e03 422 422 __cfactx_switch( &proc_cor->context, &thrd_dst->context ); 423 423 // when __cfactx_switch returns we are back in the processor coroutine 424 425 424 426 425 427 /* paranoid */ verify( 0x0D15EA5E0D15EA5Ep == thrd_dst->canary ); … … 522 524 523 525 /* paranoid */ verify( ! __preemption_enabled() ); 524 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ) , "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src );525 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit) , "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src );526 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) < ((uintptr_t)__get_stack(thrd_src->curr_cor)->base ) || thrd_src->corctx_flag, "ERROR : Returning $thread %p has been corrupted.\n StackPointer too small.\n", thrd_src ); 527 /* paranoid */ verifyf( ((uintptr_t)thrd_src->context.SP) > ((uintptr_t)__get_stack(thrd_src->curr_cor)->limit) || thrd_src->corctx_flag, "ERROR : Returning $thread %p has been corrupted.\n StackPointer too large.\n", thrd_src ); 526 528 } 527 529 -
libcfa/src/concurrency/locks.hfa
r4aba055 r2f19e03 21 21 #include "bits/weakso_locks.hfa" 22 22 #include "containers/queueLockFree.hfa" 23 23 #include "limits.hfa" 24 24 #include "thread.hfa" 25 25 … … 85 85 bool tryP(BinaryBenaphore & this) { 86 86 ssize_t c = this.counter; 87 /* paranoid */ verify( c > MIN ); 87 88 return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 88 89 } … … 92 93 ssize_t c = 0; 93 94 for () { 95 /* paranoid */ verify( this.counter < MAX ); 94 96 if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 95 97 if (c == 0) return true; -
libcfa/src/exception.c
r4aba055 r2f19e03 27 27 #include "stdhdr/assert.h" 28 28 #include "virtual.h" 29 30 #if defined( __ARM_ARCH )31 #warning FIX ME: temporary hack to keep ARM build working32 #ifndef _URC_FATAL_PHASE1_ERROR33 #define _URC_FATAL_PHASE1_ERROR 334 #endif // ! _URC_FATAL_PHASE1_ERROR35 #ifndef _URC_FATAL_PHASE2_ERROR36 #define _URC_FATAL_PHASE2_ERROR 237 #endif // ! _URC_FATAL_PHASE2_ERROR38 #endif // __ARM_ARCH39 40 29 #include "lsda.h" 41 30 … … 301 290 } 302 291 303 #if defined( __x86_64 ) || defined( __i386 ) 292 #if defined( __x86_64 ) || defined( __i386 ) || defined( __ARM_ARCH ) 304 293 // This is our personality routine. For every stack frame annotated with 305 294 // ".cfi_personality 0x3,__gcfa_personality_v0" this function will be called twice when unwinding. … … 419 408 _Unwind_GetCFA(unwind_context) + 24; 420 409 # elif defined( __ARM_ARCH ) 421 # warning FIX ME: check if anything needed for ARM 422 42; 410 _Unwind_GetCFA(unwind_context) + 40; 423 411 # endif 424 412 int (*matcher)(exception_t *) = *(int(**)(exception_t *))match_pos; … … 537 525 // HEADER 538 526 ".LFECFA1:\n" 527 #if defined( __x86_64 ) || defined( __i386 ) 539 528 " .globl __gcfa_personality_v0\n" 529 #else // defined( __ARM_ARCH ) 530 " .global __gcfa_personality_v0\n" 531 #endif 540 532 " .section .gcc_except_table,\"a\",@progbits\n" 541 533 // TABLE HEADER (important field is the BODY length at the end) … … 569 561 // No clue what this does specifically 570 562 " .section .data.rel.local.CFA.ref.__gcfa_personality_v0,\"awG\",@progbits,CFA.ref.__gcfa_personality_v0,comdat\n" 563 #if defined( __x86_64 ) || defined( __i386 ) 571 564 " .align 8\n" 565 #else // defined( __ARM_ARCH ) 566 " .align 3\n" 567 #endif 572 568 " .type CFA.ref.__gcfa_personality_v0, @object\n" 573 569 " .size CFA.ref.__gcfa_personality_v0, 8\n" … … 575 571 #if defined( __x86_64 ) 576 572 " .quad __gcfa_personality_v0\n" 577 #el se // then __i386573 #elif defined( __i386 ) 578 574 " .long __gcfa_personality_v0\n" 575 #else // defined( __ARM_ARCH ) 576 " .xword __gcfa_personality_v0\n" 579 577 #endif 580 578 ); … … 583 581 // HEADER 584 582 ".LFECFA1:\n" 583 #if defined( __x86_64 ) || defined( __i386 ) 585 584 " .globl __gcfa_personality_v0\n" 585 #else // defined( __ARM_ARCH ) 586 " .global __gcfa_personality_v0\n" 587 #endif 586 588 " .section .gcc_except_table,\"a\",@progbits\n" 587 589 // TABLE HEADER (important field is the BODY length at the end) … … 612 614 #pragma GCC pop_options 613 615 614 #elif defined( __ARM_ARCH )615 _Unwind_Reason_Code __gcfa_personality_v0(616 int version,617 _Unwind_Action actions,618 unsigned long long exception_class,619 struct _Unwind_Exception * unwind_exception,620 struct _Unwind_Context * unwind_context) {621 return _URC_CONTINUE_UNWIND;622 }623 624 __attribute__((noinline))625 void __cfaehm_try_terminate(void (*try_block)(),626 void (*catch_block)(int index, exception_t * except),627 __attribute__((unused)) int (*match_block)(exception_t * except)) {628 }629 616 #else 630 617 #error unsupported hardware architecture 631 #endif // __x86_64 || __i386 618 #endif // __x86_64 || __i386 || __ARM_ARCH -
libcfa/src/interpose.cfa
r4aba055 r2f19e03 95 95 96 96 extern "C" { 97 void __cfaabi_interpose_startup(void) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) ));98 97 void __cfaabi_interpose_startup( void ) { 99 98 const char *version = 0p; -
libcfa/src/startup.cfa
r4aba055 r2f19e03 20 20 21 21 extern "C" { 22 23 22 void __cfaabi_appready_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_APPREADY ) )); 23 void __cfaabi_appready_startup( void ) { 24 24 tzset(); // initialize time global variables 25 25 setlocale( LC_NUMERIC, getenv("LANG") ); … … 28 28 heapAppStart(); 29 29 #endif // __CFA_DEBUG__ 30 30 } // __cfaabi_appready_startup 31 31 32 33 32 void __cfaabi_appready_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_APPREADY ) )); 33 void __cfaabi_appready_shutdown( void ) { 34 34 #ifdef __CFA_DEBUG__ 35 35 extern void heapAppStop(); 36 36 heapAppStop(); 37 37 #endif // __CFA_DEBUG__ 38 38 } // __cfaabi_appready_shutdown 39 39 40 void disable_interrupts() __attribute__(( weak )) {} 41 void enable_interrupts() __attribute__(( weak )) {} 40 void disable_interrupts() __attribute__(( weak )) {} 41 void enable_interrupts() __attribute__(( weak )) {} 42 43 44 extern void __cfaabi_interpose_startup( void ); 45 extern void __cfaabi_device_startup ( void ); 46 extern void __cfaabi_device_shutdown ( void ); 47 48 void __cfaabi_core_startup( void ) __attribute__(( constructor( STARTUP_PRIORITY_CORE ) )); 49 void __cfaabi_core_startup( void ) { 50 __cfaabi_interpose_startup(); 51 __cfaabi_device_startup(); 52 } // __cfaabi_core_startup 53 54 void __cfaabi_core_shutdown( void ) __attribute__(( destructor( STARTUP_PRIORITY_CORE ) )); 55 void __cfaabi_core_shutdown( void ) { 56 __cfaabi_device_shutdown(); 57 } // __cfaabi_core_shutdown 42 58 } // extern "C" 43 59 -
tests/coroutine/fibonacci.cfa
r4aba055 r2f19e03 31 31 } 32 32 33 int next( Fibonacci & fib ) with( fib ) {34 resume( fib ); // restart last suspend35 return fn;36 }37 38 33 int main() { 39 34 Fibonacci f1, f2; 40 35 for ( 10 ) { // print N Fibonacci values 41 sout | next( f1 ) | next( f2 );36 sout | resume( f1 ).fn | resume( f2 ).fn; 42 37 } // for 43 38 } -
tests/generator/fibonacci.cfa
r4aba055 r2f19e03 8 8 // 9 9 // Author : Thierry Delisle 10 // Created On : Mon Mar 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 10 // Created On : Mon Mar 1 16:54:23 2020 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 10 21:54:14 2021 13 // Update Count : 3 14 14 // 15 16 #include <fstream.hfa> 15 17 16 18 generator Fib { … … 18 20 }; 19 21 20 void main(Fib & b) with (b) {22 void main(Fib & fib) with (fib) { 21 23 [fn1, fn] = [1, 0]; 22 24 for () { … … 29 31 Fib f1, f2; 30 32 for ( 10 ) { 31 resume( f1 ); 32 resume( f2 );33 printf("%d %d\n", f1.fn, f2.fn);33 resume( f1 ); resume( f2 ); 34 sout | f1.fn | f2.fn; 35 // sout | resume( f1 ).fn | resume( f2 ).fn; // compiler bug 34 36 } 35 36 37 } 37 38 -
tests/generator/fmtLines.cfa
r4aba055 r2f19e03 9 9 // Author : Thierry Delisle 10 10 // Created On : Thu Mar 5 16:09:08 2020 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 10 21:56:22 2021 13 // Update Count : 2 14 14 // 15 15 -
tests/generator/suspend_then.cfa
r4aba055 r2f19e03 9 9 // Author : Peter A. Buhr 10 10 // Created On : Mon Apr 29 12:01:35 2019 11 // Last Modified By : 12 // Last Modified On : 13 // Update Count : 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jun 10 21:55:51 2021 13 // Update Count : 1 14 14 // 15 15 -
tests/unified_locking/fast.cfa
r4aba055 r2f19e03 22 22 uint32_t cs() { 23 23 $thread * me = active_thread(); 24 uint32_t value = (uint32_t)me;24 uint32_t value; 25 25 lock(mo.l); 26 26 { … … 28 28 mo.id = me; 29 29 yield(random(5)); 30 value = ((uint32_t)random()) ^ ((uint32_t)me); 30 31 if(mo.id != me) sout | "Intruder!"; 31 32 mo.sum = tsum + value;
Note: See TracChangeset
for help on using the changeset viewer.