Using P Compiler and Checker
Before moving forward, we assume that you have successfully installed the P Compiler and Checker.
We introduce the P language syntax and semantics in details in the Tutorials and Language Manual. In this section, we provide an overview of the steps involved in compiling and testing a P program using the client server example in Tutorials.
Get the Client Server Example Locally
We will use the ClientServer example from Tutorial folder in P repository to describe the process of compiling and testing a P program. Please clone the P repo and navigate to the ClientServer example in Tutorial.
Clone P Repo locally:
git clone https://github.com/p-org/P.git
cd <P cloned folder>/Tutorial/1_ClientServer
Compiling a P program
There are two ways of compiling a P program:
- Using a P project file (
*.pproj
) to provides all the required inputs to the compiler or - Passing all the P files (
*.p
) along with other options (e.g.,-generate
) as commandline arguments to the compiler.
Recommendation
We recommend using the P project files to compile a P program.
P Compiler commandline options:
The P compiler provides the following commandline options:
------------------------------------------
Recommended usage:
>> pc -proj:<.pproj file>
------------------------------------------
Optional usage:
>> pc file1.p [file2.p ...][options]
options:
-t:[target project name] -- project name (as well as the generated file) if not supplied, use file1
-outputDir:[path] -- where to write the generated files
-aspectOutputDir:[path] -- where to write the generated aspectj files if not supplied, use outputDir
-generate:[C,CSharp,RVM] -- select a target language to generate
C : generate C code
CSharp : generate C# code
RVM : generate Monitor code
-h, -help, --help -- display this help message
------------------------------------------
Compiling the ClientServer project using the P Project file:
pc -proj:ClientServer.pproj
Expected Output
$ pc -proj:ClientServer.pproj
----------------------------------------
==== Loading project file: ClientServer.pproj
....... includes p file: P/Tutorial/1_ClientServer/PSrc/Server.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/Client.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/AbstractBankServer.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/ClientServerModules.p
....... includes p file: P/Tutorial/1_ClientServer/PSpec/BankBalanceCorrect.p
....... includes p file: P/Tutorial/1_ClientServer/PTst/TestDriver.p
....... includes p file: /Tutorial/1_ClientServer/PTst/Testscript.p
----------------------------------------
----------------------------------------
Parsing ..
Type checking ...
Code generation ....
Generated ClientServer.cs
----------------------------------------
Compiling ClientServer.csproj ..
Microsoft (R) Build Engine version 16.10.2+857e5a733 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
ClientServer -> P/Tutorial/1_ClientServer/POutput/netcoreapp3.1/ClientServer.dll
Build succeeded.
0 Warning(s)
0 Error(s)
----------------------------------------
P Project File Details
The P compiler does not support advanced project management features like separate compilation and dependency analysis (coming soon). The current project file interface is a simple mechanism to provide all the required inputs to the compiler in an XML format (ClientServer.pproj).
<!-- P Project file for the Client Server example -->
<Project>
<ProjectName>ClientServer</ProjectName>
<InputFiles>
<PFile>./PSrc/</PFile>
<PFile>./PSpec/</PFile>
<PFile>./PTst/</PFile>
</InputFiles>
<OutputDir>./PGenerated/</OutputDir>
</Project>
<InputFiles>
block provides all the P files that must be compiled together for this project.
In <PFile>
one can either specify the path to a P file or to a folder and the P compiler includes all the *.p
files in the folder during compilation.
The <ProjectName>
block provides the name for the project which is used as the output file name for the generated code.
The <OutputDir>
block provides the output directory for the generated code.
Finally, the <IncludeProject>
block provides a path to other P projects that must be included as dependencies during compilation.
The P compiler simply recursively copies all the P files in the dependency projects (transitively including all P files in dependent projects) and compiles them together.
This feature provides a way to split the P models for a large system into sub projects that can share models.
Compiling the ClientServer program by passing all the required inputs as commandline arguments:
pc PSpec/*.p PSrc/*.p PTst/*.p \
-generate:csharp -outputDir:PGenerated -target:ClientServer
Expected Output
----------------------------------------
....... includes p file: P/Tutorial/1_ClientServer/PSpec/BankBalanceCorrect.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/AbstractBankServer.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/Client.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/ClientServerModules.p
....... includes p file: P/Tutorial/1_ClientServer/PSrc/Server.p
....... includes p file: P/Tutorial/1_ClientServer/PTst/TestDriver.p
....... includes p file: P/Tutorial/1_ClientServer/PTst/Testscript.p
----------------------------------------
----------------------------------------
Parsing ..
Type checking ...
Code generation ....
Generated ClientServer.cs
----------------------------------------
Compiling ClientServer.csproj ..
Microsoft (R) Build Engine version 16.10.2+857e5a733 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored P/Tutorial/1_ClientServer/PGenerated/ClientServer.csproj (in 602 ms).
ClientServer -> P/Tutorial/1_ClientServer/PGenerated/POutput/netcoreapp3.1/ClientServer.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Testing a P program
Compiling the ClientServer program generates a ClientServer.dll
, this dll
is
the C# representation of the P program. The P Checker takes as input this dll
and
systematically explores behaviors of the program for the specified test case.
The path to the dll
is present in the generated compilation output, check for line:
ClientServer -> <Path>/ClientServer.dll
You can get the list of test cases defined in the P program by passing the generated dll
to the P Checker:
pmc <Path>/ClientServer.dll
Expected Output:
pmc <Path>/ClientServer.dll
Provide /method or -m flag to qualify the test method name you wish to use.
Possible options are::
PImplementation.tcSingleClient.Execute
PImplementation.tcMultipleClients.Execute
PImplementation.tcSingleClientAbstractServer.Execute
-m
or /method
parameter along with the -i
parameter to
specify how many different schedules to explore when running this test case (by default the checker explores a single schedule).
For complex systems, running for 100,000 schedules typically finds most of the easy to find bugs before
running the checker on a distributed cluster to explore billions of schedules and rule out deep bugs in the system.
So to run the tcSingleClient
test case for 100 schedules, we can use the following command:
pmc <Path>/ClientServer.dll \
-m PImplementation.tcSingleClient.Execute \
-i 100
Expected Output
. Testing <Path>/ClientServer.dll
... Method PImplementation.tcSingleClient.Execute
Starting TestingProcessScheduler in process 72009
... Created '1' testing task.
... Task 0 is using 'random' strategy (seed:3365663330).
..... Iteration #1
..... Iteration #2
..... Iteration #3
..... Iteration #4
..... Iteration #5
..... Iteration #6
..... Iteration #7
..... Iteration #8
..... Iteration #9
..... Iteration #10
..... Iteration #20
..... Iteration #30
..... Iteration #40
..... Iteration #50
..... Iteration #60
..... Iteration #70
..... Iteration #80
..... Iteration #90
..... Iteration #100
... Testing statistics:
..... Found 0 bugs.
... Scheduling statistics:
..... Explored 100 schedules: 100 fair and 0 unfair.
..... Number of scheduling points in fair terminating schedules: 11 (min), 147 (avg), 680 (max).
... Elapsed 0.8209742 sec.
. Done
There is a known bug in the ClientServer example (explained in the Tutorials) which is caught by
the tcSingleClientAbstractServer
test case. Run command:
pmc <Path>/ClientServer.dll \
-m PImplementation.tcSingleClientAbstractServer.Execute \
-i 100
Expected Output
pmc <Path>/ClientServer.dll -m PImplementation.tcSingleClientAbstractServer.Execute -i 100
. Testing <Path>/ClientServer.dll
... Method PImplementation.tcSingleClientAbstractServer.Execute
Starting TestingProcessScheduler in process 72578
... Created '1' testing task.
... Task 0 is using 'random' strategy (seed:574049731).
..... Iteration #1
... Task 0 found a bug.
... Emitting task 0 traces:
..... Writing /POutput/netcoreapp3.1/Output/ClientServer.dll/CoyoteOutput/ClientServer_0_0.txt
..... Writing /POutput/netcoreapp3.1/Output/ClientServer.dll/CoyoteOutput/ClientServer_0_0.schedule
... Elapsed 0.1971223 sec.
... Testing statistics:
..... Found 1 bug.
... Scheduling statistics:
..... Explored 1 schedule: 1 fair and 0 unfair.
..... Found 100.00% buggy schedules.
..... Number of scheduling points in fair terminating schedules: 132 (min), 132 (avg), 132 (max).
... Elapsed 0.3081316 sec.
. Done
The P checker on finding a bug generates two artifacts (highlighted in the expected output above):
(1) a textual trace file (e.g., ClientServer_0_0.txt
) that has the readable error trace representing the
sequence of steps from the intial state to the error state;
(2) a schedule file (e.g., ClientServer_0_0.schedule
) that can be used to replay the error
trace and single step through the P program with the generated error trace for debugging
(more details about debugging P error traces: here).