Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p4c compiler driver #378

Merged
merged 5 commits into from
Mar 24, 2017
Merged

p4c compiler driver #378

merged 5 commits into from
Mar 24, 2017

Conversation

hanw
Copy link
Contributor

@hanw hanw commented Mar 22, 2017

Compiler driver for bmv2, ebpf and third-party backends.

Installing the driver:

cd p4c/tools/driver
python setup.py install

Usage

usage: p4c [-h] [-v] [-debug] [-###] [-Xpreprocessor <arg>] [-Xp4c <arg>]
           [-Xassembler <arg>] [-Xlinker <arg>] [-b BACKEND] [-E] [-e] [-S]
           [-c] [-x LANGUAGE] [-I SEARCH_PATH] [-o PATH]
           source_file

positional arguments:
  source_file           Files to compile

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show version and exit
  -debug                verbose
  -###                  print (but do not run) the commands
  -Xpreprocessor <arg>  Pass <arg> to the preprocessor
  -Xp4c <arg>           Pass <arg> to the compiler
  -Xassembler <arg>     Pass <arg> to the assembler
  -Xlinker <arg>        Pass <arg> to the linker
  -b BACKEND            specify target backend
  -E                    Only run the preprocessor
  -e                    Skip the preprocessor
  -S                    Only run the preprocess and compilation steps
  -c                    Only run preprocess, compile, and assemble steps
  -x LANGUAGE           Treat subsequent input files as having type language.
  -I SEARCH_PATH        Add directory to include search path
  -o PATH               Write output to the provided path

@hanw hanw requested review from cc10512 and ChrisDodd March 22, 2017 05:04
Copy link
Contributor

@cc10512 cc10512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Needs some polishing, but this is going in the right direction.

Note that it would be useful to add a readme with the install instructions and adding a new arch-target-platform.

Also, please add copyright notices.

Unfortunately, I couldn't get it to run the compiler:

First, it requires P4C_INCLUDE_PATH env var to be defined:

p4c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4
error: P4C_INCLUDE_PATH undefined.

Then, couldn't find the backend:

p4c> export P4C_INCLUDE_PATH=`pwd`/p4include
P4C_INCLUDE_PATH=/Users/cascaval/Barefoot/Projects/P4/src/p4c/p4include
p4c> p4c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4

clang: error: no input files

p4c/build> p4c -c -b p4c-bm2-ss testdata/p4_16_samples/arith1-bmv2.p4
Unknown target: p4c-bm2-ss

p4c/build> p4c -debug -c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4
running cpp -E -x c -o ./arith1-bmv2.p4i testdata/p4_16_samples/arith1-bmv2.p4

clang: error: no input files

p4c/build> p4c -### -debug -c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4
preprocessor: cpp -E -x c -o ./arith1-bmv2.p4i testdata/p4_16_samples/arith1-bmv2.p4
p4c-bm2-ss: command not found

oh well, it's not looking in the current dir:

p4c/build> ls -l p4c-bm2-ss 
-rwxr-xr-x  1 cascaval  staff  18376136 Mar 21 18:16 p4c-bm2-ss

p4c/build> PATH=.:$PATH p4c -### -debug -c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4
preprocessor: cpp -E -x c -o ./arith1-bmv2.p4i testdata/p4_16_samples/arith1-bmv2.p4
compiler: p4c-bm2-ss --p4v=16 -o ./arith1-bmv2.json ./arith1-bmv2.p4i

Now, dry run finds it! but the real run does not:

p4c/build> PATH=.:$PATH p4c  -debug -c -b bmv2 testdata/p4_16_samples/arith1-bmv2.p4
running cpp -E -x c -o ./arith1-bmv2.p4i testdata/p4_16_samples/arith1-bmv2.p4

clang: error: no input files


def main():
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--version", dest="show_version",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we use -V for version and -v for debug?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

metavar="<arg>",
help="Pass <arg> to the linker",
action="append", default=[])
parser.add_argument("-b", dest="backend",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backend is not sufficiently specified. Think about bmv2, it may support multiple targets. In fact we have 3 factors determining the backend:

  1. the architecture (PSA, TSA, etc.)
  2. the target (simple switch, FPGA, Tofino, etc.)
  3. and the platform (bmv2, cycle accurate model, hardware)

Similar to one of the gnu triples to specify host-os-arch, we need to have an arch-target-platform triple to specify a configuration for which we want to compile, e.g., psa-ss-bmv2.

Also it would be very useful to have an option that list all the supported configurations (the equivalent of --target-help):

gcc --target-help
The following options are target specific:
  -m128bit-long-double        sizeof(long double) is 16
  -m16                        Generate 16bit i386 code
  -m32                        Generate 32bit i386 code
  -m3dnow                     Support 3DNow! built-in functions
  -m64                        Generate 64bit x86-64 code
  -m80387                     Use hardware fp
[...]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also worth noting that the include path for different architectures may be different, so we may want to let the configurations determine it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used target-arch-vendor triplet for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code still needs a bit more work to actually use the triplet info. We can probably do that after the psa work is in.


# default search path
for path in os.environ['P4C_INCLUDE_PATH'].split(':'):
if (opts.language == 'p4-16' and os.path.isdir(path + '/p4include')):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to surface the language as a top level option.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

language is already a top level options (-x p4-14 or p4-16)


import os

def config_preprocessor():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tofino should live in its backend and the install script should search the extensions folder for backend specific configurations and install them with the rest of the default configurations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

# top-down find, good for deployment
def find_bin(exe):
found_path = None
for pp in os.environ['PATH'].split(':'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might need to add the current directory to the path (see below).

@mihaibudiu
Copy link
Contributor

You should add a link to the documentation in the toplevel README.md, or add documentation in docs/README.md.

options = cfg.options[opts.backend][step]
cmd = cmd + options
# convert ['-a -b', '-c', '-d'] to ['-a', '-b', '-c', '-d']
cmd = list(itertools.chain.from_iterable(el.split() for el in cmd))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't handle quotes right. =) Try this:

https://docs.python.org/2/library/shlex.html

sys.exit(p.returncode)

if opts.debug:
print out
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not print stdout all the time? Seems like a footgun.

for root, dirs, files in os.walk(pp):
for ff in files:
if ff == exe:
found_path = pp + '/' + ff
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idiomatic thing here would be os.path.join(pp, ff).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(There's at least one more occurrence of this.)

@@ -0,0 +1 @@

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this is just an empty file?


def __init__(self, config_prefix):
self.config_prefix = config_prefix or 'p4c'
self.site_config_name = '%s.site.cfg' % (self.config_prefix)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You never refer to this.

In general, there are a lot of comments that suggest that site.cfg is special, but it seems like the code now just searches for .cfg files. You should update the comments and clarify what's happening.


def save_options(cmd, options):
for opt in options:
opt_split = opt.split(' ')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment elsewhere about this not handling quotes right.

commands['preprocessor'].insert(0, cfg.get_preprocessor(opts.backend))
commands['compiler'].insert(0, cfg.get_compiler(opts.backend))
commands['assembler'].insert(0, cfg.get_assembler(opts.backend))
commands['linker'].insert(0, cfg.get_linker(opts.backend))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems closely related to what save_options() does. Since we split() the options again later, when we actually run the commands, maybe you could just use this approach for command line options too?

Copy link
Contributor

@ChrisDodd ChrisDodd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be highly desirable to have the ste.cfg files set up in such a way that it would be easy to run things out of their individual build directories for debugging, as well as out of the install dir/prefix for post-installation.

from p4c.main import main

if __name__ == '__main__':
main()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The p4c driver program should not have a .py extension (so it can be invoked directly as p4c ...args, rather than p4c.py ...args)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after installation python setup.py install, user is able to call p4c to invoke the driver.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick question: since the rest of the repo is using autotools, why not use autotools to install the driver as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, i will add it in.


# default search path
for path in os.environ['P4C_INCLUDE_PATH'].split(':'):
if (opts.language == 'p4-16' and os.path.isdir(path + '/p4include')):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the way it is used, P4C_INCLUDE_PATH should probably be replaced by P4C_INSTALL_PREFIX, and should be specified .cfg file (possibly per target?) rather than in an envvar

config.add_compiler_option("tofino", "{}/{}.p4i".format(output_dir, source_basename))

def config_assembler():
config.add_assembler_option("tofino", "-vvvl")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-vvvvl is really only for debugging the compiler/assembler combo in a way that stores the verbose output in the assembler output dir. For futurre release, we might not want all of the -v options and might want to leave off the -l as well -- with no -l logging output will go to stderr, and with no -v, the only log output will be assembler internal ERROR messages which almost always mean the resulting config is corrupt.

But for now, this is a reasonble way of configuring things.

version = p4c.__version__,

author = p4c.__author__,
license = "BSD",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually all the software we put on p4.org is Apache 2.0.

@cc10512
Copy link
Contributor

cc10512 commented Mar 23, 2017

I was talking to @sethfowler and he thinks we're about ready to try to generate APIs from the compiler (even if they are not yet correct). So let's add an option to do the generation as well.

- installing p4c using autotools
- use target-arch-vendor triplet to specify backend
- generate p4runtime api in bmv2
- clean up
@hanw
Copy link
Contributor Author

hanw commented Mar 24, 2017

All comments should be addressed now. Please take another look.

config.add_compiler_option("bmv2-*-p4org", "{}/{}.p4i".format(output_dir, source_basename))
# generate api has part of the compilation
config.add_compiler_option("bmv2-*-p4org", "--p4runtime-file");
config.add_compiler_option("bmv2-*-p4org", "{}/{}.p4rt".format(output_dir, source_basename))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. =)

Copy link
Contributor

@cc10512 cc10512 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor issues, but overall works.
We should add a blurb in docs/README.md to document its existence.

parser.add_argument("-v", dest="debug",
help="verbose",
action="store_true", default=False)
parser.add_argument("-###", dest="dry_run",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this option was brilliant!

# -*- Python -*-

def config_preprocessor():
config.add_preprocessor_option("bmv2-*-p4org", "-E -x c -o")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for some reason, this cpp command does not work on Mac. Works fine on Linux.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to cc

os.makedirs(opts.output_directory)

commands['preprocessor'].insert(0, cfg.get_preprocessor(backend))
commands['compiler'].insert(0, cfg.get_compiler(backend))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the compiler is just built in the current directory and one does not have the current dir in the path, then it can not find the compiler, unless run with:

PATH=.:$PATH ./p4c -v ../testdata/p4_16_samples/arith-bmv2.p4

I wonder whether we should force the current directory in the path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants