annotate include/llvm/XRay/Profile.h @ 148:63bd29f05246

merged
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Wed, 14 Aug 2019 19:46:37 +0900
parents c2174574ed3a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
147
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
1 //===- Profile.h - XRay Profile Abstraction -------------------------------===//
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
2 //
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
6 //
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
8 //
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
9 // Defines the XRay Profile class representing the latency profile generated by
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
10 // XRay's profiling mode.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
11 //
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
12 //===----------------------------------------------------------------------===//
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
13 #ifndef LLVM_XRAY_PROFILE_H
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
14 #define LLVM_XRAY_PROFILE_H
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
15
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
16 #include "llvm/ADT/DenseMap.h"
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
17 #include "llvm/ADT/SmallVector.h"
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
18 #include "llvm/ADT/StringRef.h"
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
19 #include "llvm/Support/Error.h"
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
20 #include <list>
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
21 #include <utility>
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
22 #include <vector>
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
23
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
24 namespace llvm {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
25 namespace xray {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
26
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
27 class Profile;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
28
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
29 // We forward declare the Trace type for turning a Trace into a Profile.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
30 class Trace;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
31
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
32 /// This function will attempt to load an XRay Profiling Mode profile from the
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
33 /// provided |Filename|.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
34 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
35 /// For any errors encountered in the loading of the profile data from
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
36 /// |Filename|, this function will return an Error condition appropriately.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
37 Expected<Profile> loadProfile(StringRef Filename);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
38
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
39 /// This algorithm will merge two Profile instances into a single Profile
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
40 /// instance, aggregating blocks by Thread ID.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
41 Profile mergeProfilesByThread(const Profile &L, const Profile &R);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
42
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
43 /// This algorithm will merge two Profile instances into a single Profile
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
44 /// instance, aggregating blocks by function call stack.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
45 Profile mergeProfilesByStack(const Profile &L, const Profile &R);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
46
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
47 /// This function takes a Trace and creates a Profile instance from it.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
48 Expected<Profile> profileFromTrace(const Trace &T);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
49
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
50 /// Profile instances are thread-compatible.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
51 class Profile {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
52 public:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
53 using ThreadID = uint64_t;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
54 using PathID = unsigned;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
55 using FuncID = int32_t;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
56
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
57 struct Data {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
58 uint64_t CallCount;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
59 uint64_t CumulativeLocalTime;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
60 };
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
61
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
62 struct Block {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
63 ThreadID Thread;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
64 std::vector<std::pair<PathID, Data>> PathData;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
65 };
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
66
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
67 /// Provides a sequence of function IDs from a previously interned PathID.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
68 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
69 /// Returns an error if |P| had not been interned before into the Profile.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
70 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
71 Expected<std::vector<FuncID>> expandPath(PathID P) const;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
72
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
73 /// The stack represented in |P| must be in stack order (leaf to root). This
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
74 /// will always return the same PathID for |P| that has the same sequence.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
75 PathID internPath(ArrayRef<FuncID> P);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
76
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
77 /// Appends a fully-formed Block instance into the Profile.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
78 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
79 /// Returns an error condition in the following cases:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
80 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
81 /// - The PathData component of the Block is empty
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
82 ///
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
83 Error addBlock(Block &&B);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
84
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
85 Profile() = default;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
86 ~Profile() = default;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
87
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
88 Profile(Profile &&O) noexcept
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
89 : Blocks(std::move(O.Blocks)), NodeStorage(std::move(O.NodeStorage)),
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
90 Roots(std::move(O.Roots)), PathIDMap(std::move(O.PathIDMap)),
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
91 NextID(O.NextID) {}
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
92
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
93 Profile &operator=(Profile &&O) noexcept {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
94 Blocks = std::move(O.Blocks);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
95 NodeStorage = std::move(O.NodeStorage);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
96 Roots = std::move(O.Roots);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
97 PathIDMap = std::move(O.PathIDMap);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
98 NextID = O.NextID;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
99 return *this;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
100 }
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
101
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
102 Profile(const Profile &);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
103 Profile &operator=(const Profile &);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
104
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
105 friend void swap(Profile &L, Profile &R) {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
106 using std::swap;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
107 swap(L.Blocks, R.Blocks);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
108 swap(L.NodeStorage, R.NodeStorage);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
109 swap(L.Roots, R.Roots);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
110 swap(L.PathIDMap, R.PathIDMap);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
111 swap(L.NextID, R.NextID);
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
112 }
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
113
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
114 private:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
115 using BlockList = std::list<Block>;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
116
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
117 struct TrieNode {
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
118 FuncID Func = 0;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
119 std::vector<TrieNode *> Callees{};
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
120 TrieNode *Caller = nullptr;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
121 PathID ID = 0;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
122 };
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
123
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
124 // List of blocks associated with a Profile.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
125 BlockList Blocks;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
126
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
127 // List of TrieNode elements we've seen.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
128 std::list<TrieNode> NodeStorage;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
129
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
130 // List of call stack roots.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
131 SmallVector<TrieNode *, 4> Roots;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
132
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
133 // Reverse mapping between a PathID to a TrieNode*.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
134 DenseMap<PathID, TrieNode *> PathIDMap;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
135
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
136 // Used to identify paths.
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
137 PathID NextID = 1;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
138
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
139 public:
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
140 using const_iterator = BlockList::const_iterator;
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
141 const_iterator begin() const { return Blocks.begin(); }
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
142 const_iterator end() const { return Blocks.end(); }
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
143 bool empty() const { return Blocks.empty(); }
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
144 };
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
145
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
146 } // namespace xray
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
147 } // namespace llvm
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
148
c2174574ed3a LLVM 10
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents:
diff changeset
149 #endif